简体   繁体   中英

Update XML column with nodes from another XML on SQL Server

I have two tables with 1-M relationship, both containing XML columns. I have to update an XML in second table's column from another node from first table's XML's node. After struggling with the syntax to get it work, I have finally been able to get it to work. However, it is still not working. I see the rows getting updated in the messages tab but when I select the values from second table, nothing is updated. Here is a sample of my TSQL code:

DECLARE @Table1 TABLE (
    Id BIGINT PRIMARY KEY
    ,Document XML
    ,NewValue NVARCHAR(max)
    )

INSERT INTO @Table1
SELECT TOP 10 a.Id
    ,a.Document
    ,a.Document.value('(/root/metadata/name)[1]', 'nvarchar(500)') + 'blahblah'
FROM dbo.ParentTable a
ORDER BY a.Id DESC

DECLARE @Table2 TABLE (
    Id BIGINT PRIMARY KEY
    ,ParentId BIGINT
    ,OriginalXml XML
    ,ModifiedXml XML
    ,ValueType NVARCHAR(255)
    )

INSERT INTO @Table2
SELECT sm.Id
    ,sm.ParentId
    ,sm.MapXml
    ,sm.MapXml
    ,sm.ValueType
FROM dbo.ChildTable sm

PRINT 'before update'

UPDATE sm
SET ModifiedXml.modify('replace value of (//url/loc/text())[1] with sql:column("NewValue")')
FROM @Table2 sm
INNER JOIN @Table1 a ON a.Id = sm.ParentId
WHERE sm.ValueType = 'web';

UPDATE sm
SET ModifiedXml.modify('replace value of (/html/url/text())[1] with sql:column("NewValue")')
FROM @Table2 sm
INNER JOIN @Table1 a ON a.Id = sm.ParentId
WHERE sm.ValueType = 'html';

PRINT 'after update'

SELECT *
FROM @Table2

In case it is not clear, here is the XML schema for parent table:

<root>
    <metadata>
        <title></title>
        <header></header>
        <nodeN></nodeN>
    </metadata>
</root>

And here are two possible schema for child table:

<url>
    <loc>somevalue</loc>
</url>

<html>
    <url>somevlaue</url>
</html>

The problems I had been facing previously were that I had my modified XML column declared as XML. Also, I was not getting the child nodes from the parent table during select but instead trying to get the values during update time.

Update

Here is the updated SQL. This for some reason is working. The only reason I had not posted my original XML schema is because they are too long. I will double check the XPaths in my original TSQL.

DECLARE @Table1 TABLE (
    Id BIGINT PRIMARY KEY
    ,Document XML
    ,NewValue NVARCHAR(max)
    )

INSERT INTO @Table1 (
    Id
    ,Document
    )
VALUES (
    1
    ,'<root><metadata><title>title 1</title><header>header 1</header></metadata></root>'
    )

INSERT INTO @Table1 (
    Id
    ,Document
    )
VALUES (
    2
    ,'<root><metadata><title>title 2</title><header>header 2</header></metadata></root>'
    )

INSERT INTO @Table1 (
    Id
    ,Document
    )
VALUES (
    3
    ,'<root><metadata><title>title 3</title><header>header 3</header></metadata></root>'
    )

INSERT INTO @Table1 (
    Id
    ,Document
    )
VALUES (
    4
    ,'<root><metadata><title>title 4</title><header>header 4</header></metadata></root>'
    )

UPDATE @Table1
SET NewValue = Document.value('(/root/metadata/title)[1]', 'nvarchar(max)')

DECLARE @Table2 TABLE (
    Id BIGINT PRIMARY KEY
    ,ParentId BIGINT
    ,OriginalXml XML
    ,ModifiedXml XML
    ,ValueType NVARCHAR(255)
    )

INSERT INTO @Table2
VALUES (
    1
    ,1
    ,'<url><loc>old title 1</loc></url>'
    ,'<url><loc>old title 1</loc></url>'
    ,'web'
    )

INSERT INTO @Table2
VALUES (
    2
    ,3
    ,'<html><url>old title 3</url></html>'
    ,'<html><url>old title 3</url></html>'
    ,'html'
    )

PRINT 'before update'

UPDATE sm
SET ModifiedXml.modify('replace value of (//url/loc/text())[1] with sql:column("NewValue")')
FROM @Table2 sm
INNER JOIN @Table1 a ON a.Id = sm.ParentId
WHERE sm.ValueType = 'web';

UPDATE sm
SET ModifiedXml.modify('replace value of (/html/url/text())[1] with sql:column("NewValue")')
FROM @Table2 sm
INNER JOIN @Table1 a ON a.Id = sm.ParentId
WHERE sm.ValueType = 'html';

PRINT 'after update'

SELECT *
FROM @Table2

Not exactly an answer as there was nothing wrong with my code to begin with. I was finally able to see the XML schema of child table XML column and in some rows, it had some namespaces in the XML. After adding the namespaces, I was able to get the data updated.

WITH XMLNAMESPACES (DEFAULT 'http://www.sitemaps.org/schemas/sitemap/0.9') 
UPDATE ...

However that still does not explain why I was getting "x number of rows updated" yet no change in the actual data. Also, not every rows had namespaces. That means the rows that did not have namespaces should have been updated. In any case, thank you both @GriGrim and @Roman Pekar for your input.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM