繁体   English   中英

获取和更新具有特定属性的 XML 值

[英]Get and update XML value with a certain attribute

我有一个带有 xml 列的 SQL 表,该列具有这样的值,跨多行:

<array>
  <foo>
    <property name="Name">Foo 1</property>
    <property name="Gender">M</property>
    <property name="DOB">2020-01-01</property>
  </foo>
  <foo>
    <property name="Name">Foo 2</property>
    <property name="Gender">M</property>
    <property name="DOB">2020-01-02</property>
  </foo>
  <foo>
    <property name="Name">Foo 3</property>
    <property name="Gender">F</property>
    <property name="DOB">2020-01-03</property>
  </foo>
</array>

我想编写一个 SQL 语句,可以将所有出现的property["Name"]值更新为1 (删除Foo )。

我一直在尝试 SQL,例如:

select xmlcolumn.value('/array/foo[@name="Name"]/', 'nvarchar(max)')
from xmltable

以及该 XML 查询的一些变体,但没有运气弄清楚它。 结果应该是一个带有如下所示 XML 值的表(请注意,对于所有出现,具有 Name 属性的属性都设置为 1):

<array>
  <foo>
    <property name="Name">1</property>
    <property name="Gender">M</property>
    <property name="DOB">2020-01-01</property>
  </foo>
  <foo>
    <property name="Name">1</property>
    <property name="Gender">M</property>
    <property name="DOB">2020-01-02</property>
  </foo>
  <foo>
    <property name="Name">1</property>
    <property name="Gender">F</property>
    <property name="DOB">2020-01-03</property>
  </foo>
</array>

不幸的是,MS SQL Server XQuery 实现并不完全符合 XQuery 标准。 这就是为什么 XQuery .modify()方法一次更新一个。

因此,我们可以使用 XQuery .exist()方法循环更新 XML,直到没有要更新的内容为止。

请投票我的建议: https ://feedback.azure.com/d365community/idea/153a9604-7025-ec11-b6e6-000d3a4f0da0

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE  (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO @tbl (xmldata) VALUES
(N'<array>
    <foo>
        <property name="Name">Foo 1</property>
        <property name="Gender">M</property>
        <property name="DOB">2020-01-01</property>
    </foo>
    <foo>
        <property name="Name">Foo 2</property>
        <property name="Gender">M</property>
        <property name="DOB">2020-01-02</property>
    </foo>
</array>'),
(N'<array>
    <foo>
        <property name="Name">Foo 3</property>
        <property name="Gender">F</property>
        <property name="DOB">2020-01-03</property>
    </foo>
</array>');
-- DDL and sample data population, end

DECLARE @from VARCHAR(30) = '1'
   , @to VARCHAR(30) = '1'
   , @UPDATE_STATUS BIT = 1;

-- before
SELECT * FROM @tbl
WHERE xmldata.exist('/array/foo/property[@name="Name"][(./text())[1] ne sql:variable("@from")]') = 1;

WHILE @UPDATE_STATUS > 0
BEGIN
   UPDATE t
   SET xmldata.modify('replace value of (/array/foo/property[@name="Name"][(./text())[1] ne sql:variable("@from")]/text())[1]
      with (sql:variable("@to"))')
   FROM @tbl AS t
   WHERE xmldata.exist('/array/foo/property[@name="Name"][(./text())[1] ne sql:variable("@from")]') = 1;
    
   SET @UPDATE_STATUS = @@ROWCOUNT;
   PRINT @UPDATE_STATUS;
END;

-- after
SELECT * FROM @tbl;

正如@YitzhakKhabinsky 所解释的,SQL Server 不支持很多 XQuery 功能。

虽然有几种方法可以在不运行循环的情况下做到这一点。 您基本上需要重建整个 XML。

您可以使用 XQuery 执行此操作

UPDATE xmltable
SET xmlcolumn = xmlcolumn.query('
  <array>
    {
        for $foo in array/foo
        return
          <foo>
            {
              let $prop := ($foo/property[@name="Name"])[1]
              return
              <property name="{$prop/@name}">
              { substring(($prop/text())[1], 5) }
            </property>
            }
            {
              $foo/property[@name != "Name"]
            }
          </foo>
    }
  </array>
')

db<>小提琴

或者您可以使用FOR XML来执行此操作

UPDATE xmltable
SET xmlcolumn = (
    SELECT
      (
        SELECT
          v.[@name],
          CASE WHEN v.[@name] = 'Name'
            THEN SUBSTRING(v.text, 5, LEN(v.text))
            ELSE v.text
          END [text()]
        FROM x1.foo.nodes('property') x2(prop)
        CROSS APPLY (SELECT
            x2.prop.value('@name','nvarchar(1000)') [@name],
            x2.prop.value('text()[1]','nvarchar(max)') text
        ) v
        FOR XML PATH('property'), TYPE
      )
    FROM xmlcolumn.nodes('array/foo') x1(foo)
    FOR XML PATH('foo'), ROOT('array'), TYPE
);

db<>小提琴

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM