我有两个具有 1-M 关系的表,都包含 XML 列。我必须从第一个表的 XML 节点的另一个节点更新第二个表的列中的 XML。在努力使用语法使其工作之后,我终于能够让它工作。但是,它仍然无法正常工作。我看到消息选项卡中的行正在更新,但是当我从第二个表中选择值时,没有任何更新。这是我的 TSQL 代码示例:
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
如果不清楚,这里是父表的 XML 模式:
<root>
<metadata>
<title></title>
<header></header>
<nodeN></nodeN>
</metadata>
</root>
以下是子表的两种可能模式:
<url>
<loc>somevalue</loc>
</url>
<html>
<url>somevlaue</url>
</html>
我之前遇到的问题是我将修改后的 XML 列声明为 XML。此外,我没有在选择期间从父表中获取子节点,而是尝试在更新期间获取值。
更新
这是更新的 SQL。由于某种原因,这正在起作用。我没有发布我的原始 XML 模式的唯一原因是它们太长了。我将仔细检查原始 TSQL 中的 XPath。
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