使用基于属性值的T-SQL条件更新XML

时间:2012-10-17 16:23:56

标签: xml tsql sql-server-2008-r2

我有以下内容:

declare @xml XML

SET @xml = '<record priref="2" creation="2009-12-14T10:39:04">
      <field tag="aa" occ="1" lang="nl-NL">somedata</field>
      <field tag="bb" occ="1" lang="en-US">somedata</field>
      <field tag="bb" occ="2" lang="en-US">somedata</field>
      <field tag="cc" occ="1">testdata</field>
      <field tag="dd" occ="1">testdata</field>
      <field tag="ee" occ="1" lang="nl-NL">somedata</field>
      <field tag="ee" occ="1" lang="en-US">somedata</field>
    </record>' 

DECLARE @nodeCount int
DECLARE @i int

SET @i = 1

SELECT @nodeCount = @xml.value('count(/record/field/@lang)','varchar(5)') 

WHILE (@i <= @nodeCount)
BEGIN
Set @xml.modify('replace value of (/record/field/@lang)[.="en-US"][1] with "nl-NL"')

SET @i = @i + 1
END

SELECT @xml

我想有条件地更新属性@lang。

如果“tag”和“occ”(如tag = ee)的节点具有相同的属性值组合,则@lang的属性值必须保持不变。

在其他情况下,它必须像上面的查询一样改变:将'en-US'改为'nl-NL'。

任何人都知道如何做到这一点?提前谢谢!

1 个答案:

答案 0 :(得分:0)

这应该这样做

DECLARE @xml XML;

SET @xml = '<record priref="2" creation="2009-12-14T10:39:04">
      <field tag="aa" occ="1" lang="nl-NL">somedata</field>
      <field tag="bb" occ="1" lang="en-US">somedata</field>
      <field tag="dd" occ="1">testdata</field>
      <field tag="bb" occ="2" lang="en-US">somedata</field>
      <field tag="cc" occ="1">testdata</field>
      <field tag="ee" occ="1" lang="nl-NL">somedata</field>
      <field tag="ee" occ="1" lang="en-US">somedata</field>
    </record>' 

DECLARE @no INT;
DECLARE @updneeded INT;
DECLARE nodecur CURSOR LOCAL FAST_FORWARD
FOR
  SELECT  rn,
          CASE WHEN COUNT(1) OVER ( PARTITION BY tag, occ ) > 1 THEN 0
               ELSE 1
          END updneeded
  FROM    ( SELECT  ROW_NUMBER() OVER ( ORDER BY node ) AS rn,
                    node.value('@tag', 'NVARCHAR(MAX)') AS tag,
                    node.value('@occ', 'NVARCHAR(MAX)') AS occ
            FROM    @xml.nodes('/record/field') x ( node )
          ) X;
OPEN nodecur;
WHILE ( 1 = 1 ) 
  BEGIN
    FETCH NEXT FROM nodecur INTO @no, @updneeded;
    IF ( @@FETCH_STATUS <> 0 ) BREAK;

    IF ( @updneeded = 1 ) 
      SET @xml.modify('replace value of (/record/field[sql:variable("@no")]/@lang)[.="en-US"][1] with "nl-NL"');
  END
CLOSE nodecur;
DEALLOCATE nodecur;

SELECT  @xml;

然而,SQL对这些类型的操作并不是很快。在应用程序代码中执行此操作或将一些CLR功能放在一起可能更有效。