如何在 SQL 中动态更改字符串的 XML 结构
Posted
技术标签:
【中文标题】如何在 SQL 中动态更改字符串的 XML 结构【英文标题】:How can I dynamically change the XML structure of a string in SQL 【发布时间】:2022-01-02 04:41:09 【问题描述】:我需要一个 SQL 脚本,它可以从数据库 [varchar(max)] 中提取一个 XML 字符串,对其进行检查并更新它如果它适合特定情况。
假设我的 xml 格式如下:
<root>
<level1>
<level2>
<level3 />
<level3 />
</level2>
</level1>
<level1>
<level2>
<level3>
<level4>
<level5>
<level6 here="now is the time for XYZ">
<options>
<option this="that" />
<option me="you" />
</options>
</level6>
</level5>
</level4>
</level3>
</level2>
</level1>
<level1>
<level2>
<level3>
<level4>
<level5>
<level6 here="this one is not of interest">
<options>
<option this="that" />
<option me="you" />
</options>
</level6>
</level5>
</level4>
</level3>
</level2>
</level1>
<level1>
<level2>
<level3>
<level4>
<level5>
<level6 here="now is the time for ABC">
<options>
<option this="that" />
<option me="you" />
<option here="now" />
</options>
</level6>
</level5>
</level4>
</level3>
</level2>
</level1>
</root>
所以,我要做的是更新所有名称为“level6”且具有名为“here”的属性的元素,其值开始为“now is the time”。所以,这应该只匹配上面的两个元素。
但是,这不是唯一的选择标准。选项列表不能包含<option here="now" />
。所以,这应该让我们只需要更新一个元素。
<level6 here="now is the time for XYZ">
<options>
<option this="that" />
<option me="you" />
</options>
</level6>
对于那个元素,然后我想添加缺少的<option here="now" />
,这样就变成了:
<level6 here="now is the time for XYZ">
<options>
<option this="that" />
<option me="you" />
<option here="now" />
</options>
</level6>
所以,最终结果应该是:
<root>
<level1>
<level2>
<level3 />
<level3 />
</level2>
</level1>
<level1>
<level2>
<level3>
<level4>
<level5>
<level6 here="now is the time for XYZ">
<options>
<option this="that" />
<option me="you" />
<option here="now" /> // <- this one new
</options>
</level6>
</level5>
</level4>
</level3>
</level2>
</level1>
<level1>
<level2>
<level3>
<level4>
<level5>
<level6 here="this one is not of interest">
<options>
<option this="that" />
<option me="you" />
</options>
</level6>
</level5>
</level4>
</level3>
</level2>
</level1>
<level1>
<level2>
<level3>
<level4>
<level5>
<level6 here="now is the time for ABC">
<options>
<option this="that" />
<option me="you" />
<option here="now" />
</options>
</level6>
</level5>
</level4>
</level3>
</level2>
</level1>
</root>
假设我可以将数据库中的数据读入字符串,并且我知道如何更新数据库,那么实际上就是如何在SQL(SQL Server)中操作xml字符串。
【问题讨论】:
你试过什么? :) 【参考方案1】:您可以使用带有.modify
函数的XML DML(数据修改)来更改XML。
SET @xml.modify('
insert <option here="now" />
as last into
( /root/level1/level2/level3/level4/level5/level6
[substring(@here, 1, 15) = "now is the time"]
/options [not(/option[@here = "now"])]
)[1]');
它的工作原理如下:
insert <option here="now" />
这是我们要插入的值
as last into
追随所选节点的其他子节点
/root/level1/level2/level3/level4/level5/level6
这让我们知道level6
节点
[substring(@here, 1, 15) = "now is the time"]
表示节点具有以该值开头的 here
属性。您必须修改长度参数以匹配您正在比较的值。 XQuery 中没有LIKE
/options [not(/option[@here = "now"])]
我们寻找具有 no option
子节点的 options
子节点,而子节点又具有 here="now"
属性
[1]
第一个这样的节点
如果需要修改单个 XML 文档中的多个节点,则需要循环运行
DECLARE @i int = 20; --max nodes
WHILE @xml.exist('
/root/level1/level2/level3/level4/level5/level6
[substring(@here, 1, 15) = "now is the time"]
/options [not(option[@here = "now"])]
') = 1
BEGIN
SET @xml.modify('
insert <option here="now" /> as last into
( /root/level1/level2/level3/level4/level5/level6
[substring(@here, 1, 15) = "now is the time"]
/options [not(option[@here = "now"])]
)[1]');
SET @i -= 1;
IF @i = 0
BREAK;
END;
你也可以对整张桌子这样做
DECLARE @i int = 20; --max nodes
WHILE EXISTS (SELECT 1
FROM YourTable
WHERE XmlColumn.exist('
/root/level1/level2/level3/level4/level5/level6
[substring(@here, 1, 15) = "now is the time"]
/options [not(option[@here = "now"])]
') = 1)
BEGIN
UPDATE t
SET XmlColumn.modify('
insert <option here="now" /> as last into
( /root/level1/level2/level3/level4/level5/level6
[substring(@here, 1, 15) = "now is the time"]
/options [not(option[@here = "now"])]
)[1]')
FROM YourTable t
WHERE XmlColumn.exist('
/root/level1/level2/level3/level4/level5/level6
[substring(@here, 1, 15) = "now is the time"]
/options [not(option[@here = "now"])]
') = 1;
SET @i -= 1;
IF @i = 0
BREAK;
END;
对于非常大的数据集,使用 XQuery 重建整个 XML 可能会更快,并使用 Constructed XML 添加额外的节点。
db<>fiddle
【讨论】:
以上是关于如何在 SQL 中动态更改字符串的 XML 结构的主要内容,如果未能解决你的问题,请参考以下文章