如何将元素插入到xml列中,而不知道树是否已经存在?

Sco*_*t C 10 xml sql-server sql-server-2008

我在SQL Server 2008中有一个值表,我希望将值插入到另一个表的匹配行中的XML列中.xml列可能包含也可能没有所有标记通向我要插入的元素.

我可以通过多个更新/ xml.modify语句来实现这一点,以确保在插入元素之前存在标记,但这似乎非常低效,如果我想插入5或10个标签深度怎么办?

这是SQL小提琴中的一个创建示例

设置是我有2个表(简化/组成这里以使一个可理解的方案)

CREATE TABLE tableColors (id nvarchar(100), color  nvarchar(100))
CREATE TABLE xmlTable (id nvarchar(100), xmlCol xml)`
Run Code Online (Sandbox Code Playgroud)

我需要将元素<root><colors><color>tableColors.color</color></colors></root>插入到xmlTable中,其中id匹配且元素尚不存在.xmlCol可以包含更多元素,甚至可以是空白.颜色标签为0或许多,颜色标签为0或1.

将元素插入正确位置的最终语句是有意义的,但如果父标记尚不存在则不起作用.

UPDATE xmlTable
SET xmlCol.modify(' insert <color>{sql:column("color")}</color> as first into (/root/colors)[1] ')
FROM xmlTable
INNER JOIN tableColors ON xmlTable.id = tableColors.id
WHERE xmlCol.exist('/root/colors/color[(text()[1]) = sql:column("color")]') = 0 
Run Code Online (Sandbox Code Playgroud)

因此,我需要/root/colors在运行此更新语句之前确保存在.请告诉我,我错过了一些东西,我不必明确地插入root(如果为空),然后将颜色插入root.

为了进一步说明,这里是将新元素插入/ root/colors之前和之后:

New Element              XML before                                           XML after
<color>blue</color>       -blank-                                              <root><colors><color>blue</color></colors></root>
<color>green</color>      <root><vegitation>yes</vegitation></root>            <root><vegitation>yes</vegitation><colors><color>green</color></colors></root>
<color>white</color>      <root><colors><color>brown</color></colors></root>   <root><colors><color>brown</color><color>white</color></colors></root>
Run Code Online (Sandbox Code Playgroud)

再一次,这里是SQL小提琴中的一个完整示例,我实现了我想要的东西,但必须有更好的方法.我错过了什么?

Bri*_*ler 1

您可以在插入语句中包含嵌套结构,并且只需一次更新即可完成此操作,如下所示:

UPDATE #xmlTable
SET xmlCol.modify('
insert if (count(/root)=0) then <root><colors><color>{sql:column("color")}</color></colors></root> 
else (if (count(/root/colors)=0) then <colors><color>{sql:column("color")}</color></colors> 
else <color>{sql:column("color")}</color>) as first into 
(if (count(/root)=0) then (/) else (if (count(/root/colors)=0) then (/root) else (/root/colors)))[1]')
FROM #xmlTable
INNER JOIN #tableColors
    ON #xmlTable.id = #tableColors.id
WHERE xmlCol.exist('/root/colors/color[(text()[1])=sql:column("color")]') = 0 
Run Code Online (Sandbox Code Playgroud)