太好了,您找到了解决方案(投票赞成),只是一些提示:
一个三行的虚拟表:
DECLARE @DummyTable TABLE(ID INT IDENTITY, Comment VARCHAR(100), MasterObjectIDs XML);
INSERT INTO @DummyTable VALUES
('Your example', N'<ArrayOfPickListObjectBaseModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PickListObjectBaseModel>
<MasterObjectId>3964405</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>405716</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>5872525</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
</ArrayOfPickListObjectBaseModel>'
)
,('More than one target', N'<ArrayOfPickListObjectBaseModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PickListObjectBaseModel>
<MasterObjectId>3964405</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>405716</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>3964405</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
</ArrayOfPickListObjectBaseModel>'
),
('no target', N'<ArrayOfPickListObjectBaseModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PickListObjectBaseModel>
<MasterObjectId>1111</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>405716</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
<PickListObjectBaseModel>
<MasterObjectId>5872525</MasterObjectId>
<IsSelected>false</IsSelected>
</PickListObjectBaseModel>
</ArrayOfPickListObjectBaseModel>');
--变量
DECLARE @oldId INT = 3964405;
DECLARE @newId INT = 99999;
--我使用xml.exist(),比您过滤目标行的方法更快:
UPDATE @DummyTable
SET MasterObjectIDs.modify('replace value of
(//PickListObjectBaseModel/MasterObjectId[text() = sql:variable("@oldId")]/text())[1]
with sql:variable("@newId")')
FROM @DummyTable p
WHERE p.MasterObjectIDs.exist('/ArrayOfPickListObjectBaseModel/PickListObjectBaseModel/MasterObjectId[text()=sql:variable("@oldId")]') = 1;
--结果
SELECT @@ROWCOUNT; --good the filter hits only 2 rows
SELECT * FROM @DummyTable; --bad, the XML more than one occurances is not edited everywhere...
如果您要查找的 id 可能在一个 XML 中出现多次,您的方法将不适用于所有这些,仅适用于第一个...
您可以循环运行您的语句,直到exist() 返回0,或者您可以分解 XML 并从头开始重建它,如下所示:
WITH UpdateableCTE AS
(
SELECT p.MasterObjectIds AS Original
,B.NewXML
FROM @DummyTable AS p
CROSS APPLY
(
SELECT
(
SELECT CASE WHEN plo.value(N'(MasterObjectId/text())[1]','int')=@oldId THEN @newId ELSE plo.value(N'(MasterObjectId/text())[1]','int') END AS MasterObjectId
,plo.value(N'(IsSelected/text())[1]','nvarchar(max)') AS IsSelected
FROM MasterObjectIDs.nodes(N'/ArrayOfPickListObjectBaseModel/PickListObjectBaseModel') AS A(plo)
FOR XML PATH(N'PickListObjectBaseMode'),ROOT(N'ArrayOfPickListObjectBaseModel'),TYPE
)
) AS B(NewXML)
WHERE p.MasterObjectIDs.exist('/ArrayOfPickListObjectBaseModel/PickListObjectBaseModel/MasterObjectId[text()=sql:variable("@oldId")]') = 1
)
UPDATE UpdateableCTE SET Original=NewXML;
--只有2行受到影响
SELECT @@ROWCOUNT; --good the filter hits only 2 rows
SELECT * FROM @DummyTable; --all occurances are switched...