用另一个节点替换一个节点有点棘手。以下代码将首先使用可更新的 CTE 找到合适的 category,获取其 XmlData,然后使用 CTE 到 UPDATE 产品的 XmlData 和 insert 新节点.
我们现在的问题是:类别存在两次:一次是新节点,第二次是旧节点。当我们插入 as first 时,我们可以肯定,第二次出现是要删除的:
DECLARE @Category Table(Id int, ParentID int, XmlData XML);
INSERT INTO @Category
VALUES (
1,
0,
'<category>
<item>BMW</item>
<item>MERCEDES</item>
<item>AUDI</item>
<item>WOLKSVAGEN</item>
</category>'
);
DECLARE @Product Table (Id int, XmlData xml);
INSERT INTO @Product
VALUES (
1,
'<item>
<category id="1" />
<name>Carburetor</name>
<model>MDS343498</model>
<price>$3000</price>
<stock>123</stock>
</item>'
);
--可更新的CTE
WITH UpdateableCTE AS
(
SELECT p.Id
,p.XmlData
,Cat.XmlData AS XmlToInsert
FROM @Product AS p
CROSS APPLY (SELECT c.XmlData FROM @Category AS c WHERE Id=p.XmlData.value('(/item/category/@id)[1]','int')) AS Cat
)
UPDATE UpdateableCTE
SET XmlData.modify(N'insert sql:column("XmlToInsert") as first into (/item)[1]');
--删除第二次出现
UPDATE @Product SET XmlData.modify(N'delete /item[1]/category[2]')
--XmlData中的结果:
SELECT * FROM @Product
<item>
<category>
<item>BMW</item>
<item>MERCEDES</item>
<item>AUDI</item>
<item>WOLKSVAGEN</item>
</category>
<name>Carburetor</name>
<model>MDS343498</model>
<price>$3000</price>
<stock>123</stock>
</item>
OT:您可能想将WOLKSVAGEN 更正为VOLKSWAGEN :-)
UPDATE 保留属性<category id="1">,在上面的方法中丢失了:
我使用FLWOR-查询来预先组织XmlToInsert
WITH UpdateableCTE AS
(
SELECT p.Id
,p.XmlData
,Cat.XmlData.query
(
N'<category id="{sql:column("CatId")}">
{/category/item}
</category>'
) AS XmlToInsert
FROM @Product AS p
CROSS APPLY (SELECT c.Id AS CatId, c.XmlData FROM @Category AS c WHERE Id=p.XmlData.value('(/item/category/@id)[1]','int')) AS Cat
)
UPDATE UpdateableCTE
SET XmlData.modify(N'insert sql:column("XmlToInsert") as first into (/item)[1]');
UPDATE @Product SET XmlData.modify(N'delete /item[1]/category[2]')
SELECT * FROM @Product
更新 2:不同的方法动态
这样试试
WITH CTE AS
(
SELECT p.Id
,p.XmlData
,Cat.XmlData.query
(
N'<category id="{sql:column("CatId")}">
{/category/item}
</category>'
) AS XmlToInsert
FROM @Product AS p
CROSS APPLY (SELECT TOP 1 c.Id AS CatId, c.XmlData FROM @Category AS c WHERE Id=p.XmlData.value('(/item/category/@id)[1]','int')) AS Cat
)
SELECT XmlToInsert AS [node()]
,XmlData.query('/item/*[local-name()!="category"]')
FROM CTE
FOR XML PATH('item')