'Find a string with in a TEXT type column that contains an XML file and replace a value in SQL Server

Update: The column that has the XML file has a data type of text.


Update 2 (This helped me use xml functions instead of using charindex to manipulate the data): I created a temp table #tmpXML (id int, xmlField XML). id is the Primary key of my main table and xmlField is the XML value from the text type field. I used XML functions on the XML data field in the temp table and got all the values I needed and I updated my main table with these values.

I found this method to be more efficient and clean than using sql server functions like charindex and substring. This is the reason why I accepted the answer because it helped me use xml functions. Just wanted to clarify.


I have a column called Settings that contains xml file with user settings.

For example I have 3 users that have the following rows for this column.

XML for the first user id 1:

<owner>
    <product userid="1" productid="3" region="North" country="Usa" ></product>
</owner>

XML for the first user id 2:

<owner>
    <product userid="2" productid="3" selectedView="true" region="North" state="AZ" country="Usa" ></product>
</owner>

XML for the first user id 3:

<owner>
    <product userid="3" productid="3" selectedView="true" region="South" isSelected="true" state="AZ" country="Usa" ></product>
</owner>

As you can see, the attributes can be in any order within the XML files for each user. I have to update all the users to have region = "East". I tried doing it using CharIndex and substring but it's getting too confusing. Any ideas on how to do this? Thanks!



Solution 1:[1]

You could use a case statement in the select Case When colName like '%NORTH%' then replace (colName, NORTH, NEWTEXT When colName like '%SOUTH%' etc

You could also create a stored function

Solution 2:[2]

Please try the following solution.

Text is a deprecated data type in the MS SQL Server. I used NVARCHAR(MAX) data type to distinguish it from the natural XML data type for the XML data.

SQL

DECLARE @tbl TABLE (id int primary key, Settings NVARCHAR(MAX));
INSERT @tbl VALUES
(1,'<owner>
    <product userid="1" productid="3" region="North" country="Usa" ></product>
</owner>'),
(2,'<owner>
    <product userid="2" productid="3" selectedView="true" region="North" state="AZ" country="Usa" ></product>
</owner>'),
(3,'<owner>
    <product userid="3" productid="3" selectedView="true" region="South" isSelected="true" state="AZ" country="Usa" ></product>
</owner>');

WITH rs AS
(
    SELECT * 
    FROM @tbl
        CROSS APPLY (SELECT TRY_CAST(Settings AS XML)
            .query('<owner><product>
                {
                    for $x in /owner/product/@*
                    return if(local-name($x) ne "region") then $x
                        else attribute region {"East"}
                }
            </product></owner>')) t(x)
)
UPDATE rs
SET rs.Settings  = TRY_CAST(x AS NVARCHAR(MAX));

-- test
SELECT * FROM @tbl;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2