sql-server - 使用基于连接的当前节点值从辅助表更新 xml 节点值

标签 sql-server xml join xml.modify

dbo.table_a包含XML列foo。每行的 XML 列中都有一个 XML 树。 辅助表dbo.table_b包含旧值old_val和新值new_val

XML 树看起来像这样

<root>
  <Customer>
    <Name>ACME</Name>
  </Customer>
  <Def>
    <Enabled>true</Enabled>
    <CIds>
      <Id>ABC</Id>
      <Id>DEF</Id>
    </CIds>
  </Def>
</root>

请注意,/root/Def/CIds 可以包含零个或多个名为 Id 的子节点。

dbo.table_b 看起来像这样

+---------+---------+
| old_val | new_val |
+---------+---------+
| ABC     |     123 |
| DEF     |     456 |
+---------+---------+

我需要通过将当前 xml 节点值与 old_val 上的 dbo.table_b 连接并替换 xml 来替换每个 Id 的值节点值与 new_val。 ABC 应替换为 123,DEF 替换为 456

最佳答案

没有简单的方法可以实现这一点,因为即使是现在,2018 年,replace value of XML 方法仍然不支持多个节点的修改。

最简单的方法是插入+删除策略,如下例所示:

declare @TableA table (
    Id int identity(1,1) primary key,
    XData xml not null
);

declare @TableB table (
    OldValue varchar(50),
    NewValue int
);

insert into @TableA (XData)
select N'<root>
  <Customer>
    <Name>ACME</Name>
  </Customer>
  <Def>
    <Enabled>true</Enabled>
    <CIds>
      <Id>ABC</Id>
      <Id>DEF</Id>
    </CIds>
  </Def>
</root>';

insert into @TableB (OldValue, NewValue)
values
    ('ABC', 123),
    ('DEF', 456);

-- Before
select * from @TableA;

update a set XData.modify('insert sql:column("sq.NewData") after /root[1]/Def[1]/CIds[1]')
from @TableA a
    cross apply (
        select b.NewValue as [Id]
        from @TableB b
        where a.XData.exist('/root/Def/CIds/Id[text() = sql:column("b.OldValue")]') = 1
        for xml path(''), type, root('CIds')
    ) sq(NewData);

update a set XData.modify('delete /root[1]/Def[1]/CIds[1]')
from @TableA a;

-- After
select * from @TableA;

它的弱点是它会重建整个 /CIds 节点,因此如果其中有任何其他数据(例如属性),重新创建可能会很麻烦。在这种情况下,使用 FLWOR 更新可能会取得更好的成功,但与其他选项相比,它们往往相当慢。

或者,您可以在循环中运行一系列原子更新。尽管听起来令人不快,但它实际上会起作用,特别是如果您的实际 XML 比提供的示例复杂得多。

关于sql-server - 使用基于连接的当前节点值从辅助表更新 xml 节点值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51885869/

相关文章:

Android - ellipsize ="end"不显示三个点

同一表中的Mysql子查询COUNT返回NULL

sql - 将表情符号/表情符号添加到 SQL Server 表

Textview和复选框的Android布局对齐

java - 如何在Android中仅以纵向模式在10英寸平板电脑中进行设计?

sql - 使用一个 SELECT 而不是两个来服务于旁加载的 API 请求?

mysql - 全文匹配表达式可以在连接条件内工作吗

sql - 如何在不指定架构名称的情况下编写查询?

sql - 确定 SQL Server View 中引用的表

sql - 有没有办法删除已经绑定(bind)到存储过程的用户定义表类型?