如何用 XQuery 中节点的另一个值替换值?
How to replace value with another value of a node in XQuery?
我在 SQL Server 14.0 中有一个 table,称为 Users 。有多个用户,每个用户都有一个名为 PermissionData 的列数据,它位于 XML 格式。
以下是 XML :
<Policy>
<Permissions>
<Item>
<Key>Hello</Key>
</Item>
<Item>
<Key>Bye</Key>
</Item>
</Permissions>
</Policy>
所以我想用 GoodBye 值替换所有 Bye。
一些用户可能有这个 Bye 值,也可能没有。其他一些用户可以将此 Bye 值作为第一个键或第二个键或第三个键。因此,由于顺序可能不同,我不能只在每个键上执行 [2]。
最终结果应该是这样的:
<Policy>
<Permissions>
<Item>
<Key>Hello</Key>
</Item>
<Item>
<Key>GoodBye</Key>
</Item>
</Permissions>
</Policy>
任何人都可以帮我编写一个 XQuery 来更新用户 table 中所有用户的键值吗?以下是我尝试编写的查询,但它不起作用。
UPDATE Users
SET PermissionData.modify('replace value of (/Policy/Permissions/Item/Key)
with( if((/Policy/Permissions/Item/Key/text())="Bye")
then "GoodBye"
else ()
)')
请尝试以下解决方案。
要点:
- XML 区分大小写,这就是使用
lower-case()
函数的原因。
- XQuery
.modify()
方法一次只更新一个节点。
- 如果 XML 根本没有
<Key>...</Key>
元素,或者它有一个不同的元素
值,.modify()
方法不会影响XML,也不会出错。
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (id INT IDENTITY PRIMARY KEY, PermissionData XML);
INSERT INTO @tbl (PermissionData ) VALUES
(N'<Policy>
<Permissions>
<Item>
<Key>Hello</Key>
<Value>
<WorkPermissions>
<Operations>
<Item>Say1</Item>
<Item>Say2</Item>
</Operations>
</WorkPermissions>
</Value>
</Item>
<Item>
<Key>Bye</Key>
<Value>
<WorkPermissions>
<Operations>
<Item>Say1</Item>
<Item>Say2</Item>
</Operations>
</WorkPermissions>
</Value>
</Item>
</Permissions>
</Policy>');
-- DDL and sample data population, end
DECLARE @currentValue VARCHAR(30) = 'bye' -- keep it lower case
, @newValue VARCHAR(30) = 'GoodBye';
UPDATE @tbl
SET PermissionData.modify('
replace value of (/Policy/Permissions/Item/Key[lower-case(./text()[1])=sql:variable("@currentValue")]/text())[1]
with (sql:variable("@newValue"))
');
-- test
SELECT * FROM @tbl;
输出XML
<Policy>
<Permissions>
<Item>
<Key>Hello</Key>
<Value>
<WorkPermissions>
<Operations>
<Item>Say1</Item>
<Item>Say2</Item>
</Operations>
</WorkPermissions>
</Value>
</Item>
<Item>
<Key>GoodBye</Key>
<Value>
<WorkPermissions>
<Operations>
<Item>Say1</Item>
<Item>Say2</Item>
</Operations>
</WorkPermissions>
</Value>
</Item>
</Permissions>
</Policy>
我在 SQL Server 14.0 中有一个 table,称为 Users 。有多个用户,每个用户都有一个名为 PermissionData 的列数据,它位于 XML 格式。 以下是 XML :
<Policy>
<Permissions>
<Item>
<Key>Hello</Key>
</Item>
<Item>
<Key>Bye</Key>
</Item>
</Permissions>
</Policy>
所以我想用 GoodBye 值替换所有 Bye。 一些用户可能有这个 Bye 值,也可能没有。其他一些用户可以将此 Bye 值作为第一个键或第二个键或第三个键。因此,由于顺序可能不同,我不能只在每个键上执行 [2]。
最终结果应该是这样的:
<Policy>
<Permissions>
<Item>
<Key>Hello</Key>
</Item>
<Item>
<Key>GoodBye</Key>
</Item>
</Permissions>
</Policy>
任何人都可以帮我编写一个 XQuery 来更新用户 table 中所有用户的键值吗?以下是我尝试编写的查询,但它不起作用。
UPDATE Users
SET PermissionData.modify('replace value of (/Policy/Permissions/Item/Key)
with( if((/Policy/Permissions/Item/Key/text())="Bye")
then "GoodBye"
else ()
)')
请尝试以下解决方案。
要点:
- XML 区分大小写,这就是使用
lower-case()
函数的原因。 - XQuery
.modify()
方法一次只更新一个节点。 - 如果 XML 根本没有
<Key>...</Key>
元素,或者它有一个不同的元素 值,.modify()
方法不会影响XML,也不会出错。
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (id INT IDENTITY PRIMARY KEY, PermissionData XML);
INSERT INTO @tbl (PermissionData ) VALUES
(N'<Policy>
<Permissions>
<Item>
<Key>Hello</Key>
<Value>
<WorkPermissions>
<Operations>
<Item>Say1</Item>
<Item>Say2</Item>
</Operations>
</WorkPermissions>
</Value>
</Item>
<Item>
<Key>Bye</Key>
<Value>
<WorkPermissions>
<Operations>
<Item>Say1</Item>
<Item>Say2</Item>
</Operations>
</WorkPermissions>
</Value>
</Item>
</Permissions>
</Policy>');
-- DDL and sample data population, end
DECLARE @currentValue VARCHAR(30) = 'bye' -- keep it lower case
, @newValue VARCHAR(30) = 'GoodBye';
UPDATE @tbl
SET PermissionData.modify('
replace value of (/Policy/Permissions/Item/Key[lower-case(./text()[1])=sql:variable("@currentValue")]/text())[1]
with (sql:variable("@newValue"))
');
-- test
SELECT * FROM @tbl;
输出XML
<Policy>
<Permissions>
<Item>
<Key>Hello</Key>
<Value>
<WorkPermissions>
<Operations>
<Item>Say1</Item>
<Item>Say2</Item>
</Operations>
</WorkPermissions>
</Value>
</Item>
<Item>
<Key>GoodBye</Key>
<Value>
<WorkPermissions>
<Operations>
<Item>Say1</Item>
<Item>Say2</Item>
</Operations>
</WorkPermissions>
</Value>
</Item>
</Permissions>
</Policy>