XQuery adding or replacing attribute in single SQL update command

喜你入骨 提交于 2019-12-10 17:24:21

问题


I have a Table with an XML column, I want to update the xml to insert attribute or to change the attribute value if the attribute already exists.

Let's say the starting xml is: < d />

Inserting:

UPDATE Table 
set XmlCol.modify('insert attribute att {"1"} into /d[1]')

Changing:

UPDATE Table
set XmlCol.modify('replace value of /d[1]/@att with "1"')

insert will fail if the attribute already exists, replace will fail if the attribute doesn't exists. I have tried to use 'if' but I don't think it can work, there error I get: "XQuery [modify()]: Syntax error near 'attribute', expected 'else'."

IF attempt

UPDATE Table 
set XmlCol.modify('if empty(/d[1]/@att) 
                   then insert attribute att {"1"} into /d[1]
                   else replace value of /d[1]/@att with "1"')

Currently I select the xml into a variable and then modify it using T-SQL and then updating the column with new xml, this requires me to lock the row in a transaction and is probably more expensive for the DB.


回答1:


From what I can tell, you can't do this with single statement. You can use the exist() method to accomplish that with two update statements.

DECLARE @TestTable TABLE
(
    Id int,
    XmlCol xml
);

INSERT INTO @TestTable (Id, XmlCol)
VALUES
    (1, '<d att="1" />'),
    (2, '<d />'),
    (3, '<d att="3" />');

SELECT * FROM @TestTable;

UPDATE @TestTable
SET XmlCol.modify('replace value of /d[1]/@att with "1"')
WHERE XmlCol.exist('(/d[1])[not(empty(@att))]') = 1;

UPDATE @TestTable
SET XmlCol.modify('insert attribute att {"1"} into /d[1]')
WHERE XmlCol.exist('(/d[1])[empty(@att)]') = 1;

SELECT * FROM @TestTable;

The output from the final select is:

Id          XmlCol
----------- -------------------
1           <d att="1" />
2           <d att="1" />
3           <d att="1" />



回答2:


There is a slightly better way than Tommys:

DECLARE @TestTable TABLE
(
    Id int,
    XmlCol xml
);

INSERT INTO @TestTable (Id, XmlCol)
VALUES
    (1, '<UserSettings> </UserSettings>'),
    (2, '<UserSettings><timeout>3</timeout> </UserSettings>'),
    (3, '<UserSettings> </UserSettings>');

UPDATE @TestTable
SET XmlCol.modify('replace value of (/UserSettings/timeout/text())[1] with "1"')
WHERE Id = 3 and XmlCol.exist('/UserSettings/timeout') = 1;
IF @@ROWCOUNT=0
    UPDATE @TestTable
    SET XmlCol.modify('insert <timeout>5</timeout> into (/UserSettings)[1] ')
    WHERE Id = 3;

SELECT * FROM @TestTable;

The solution is a combination of Tommys and simple SQL and required only 1 SQL UPDATE if the column exist. Tommys always recuire two updates.



来源:https://stackoverflow.com/questions/3854308/xquery-adding-or-replacing-attribute-in-single-sql-update-command

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!