如何用 XQuery 中节点的另一个值替换值?

How to replace value with another value of a node in XQuery?

我在 SQL Server 14.0 中有一个 table,称为 Users 。有多个用户,每个用户都有一个名为 PermissionData 的列数据,它位于 XML 格式。 以下是 XML :

<Policy>
      <Permissions>
        <Item>
          <Key>Hello</Key>
        </Item>
        <Item>
          <Key>Bye</Key>
        </Item>
      </Permissions>
    </Policy>

所以我想用 GoodBye 值替换所有 Bye。 一些用户可能有这个 Bye 值,也可能没有。其他一些用户可以将此 Bye 值作为第一个键或第二个键或第三个键。因此,由于顺序可能不同,我不能只在每个键上执行 [2]。

最终结果应该是这样的:

 <Policy>
  <Permissions>
    <Item>
      <Key>Hello</Key>
    </Item>
    <Item>
      <Key>GoodBye</Key>
    </Item>
  </Permissions>
</Policy>

任何人都可以帮我编写一个 XQuery 来更新用户 table 中所有用户的键值吗?以下是我尝试编写的查询,但它不起作用。

UPDATE Users
SET PermissionData.modify('replace value of (/Policy/Permissions/Item/Key)
 with( if((/Policy/Permissions/Item/Key/text())="Bye")
      then "GoodBye"
      else () 
     )')

请尝试以下解决方案。

要点:

  • XML 区分大小写,这就是使用 lower-case() 函数的原因。
  • XQuery .modify() 方法一次只更新一个节点。
  • 如果 XML 根本没有 <Key>...</Key> 元素,或者它有一个不同的元素 值,.modify()方法不会影响XML,也不会出错。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (id INT IDENTITY PRIMARY KEY, PermissionData  XML);
INSERT INTO @tbl (PermissionData ) VALUES
(N'<Policy>
    <Permissions>
        <Item>
            <Key>Hello</Key>
            <Value>
                <WorkPermissions>
                    <Operations>
                        <Item>Say1</Item>
                        <Item>Say2</Item>
                    </Operations>
                </WorkPermissions>
            </Value>
        </Item>
        <Item>
            <Key>Bye</Key>
            <Value>
                <WorkPermissions>
                    <Operations>
                        <Item>Say1</Item>
                        <Item>Say2</Item>
                    </Operations>
                </WorkPermissions>
            </Value>
        </Item>
    </Permissions>
</Policy>');
-- DDL and sample data population, end

DECLARE @currentValue VARCHAR(30) = 'bye' -- keep it lower case
    , @newValue VARCHAR(30) = 'GoodBye';

UPDATE @tbl
SET PermissionData.modify('  
  replace value of (/Policy/Permissions/Item/Key[lower-case(./text()[1])=sql:variable("@currentValue")]/text())[1]  
  with (sql:variable("@newValue"))  
');

-- test
SELECT * FROM @tbl;

输出XML

<Policy>
  <Permissions>
    <Item>
      <Key>Hello</Key>
      <Value>
        <WorkPermissions>
          <Operations>
            <Item>Say1</Item>
            <Item>Say2</Item>
          </Operations>
        </WorkPermissions>
      </Value>
    </Item>
    <Item>
      <Key>GoodBye</Key>
      <Value>
        <WorkPermissions>
          <Operations>
            <Item>Say1</Item>
            <Item>Say2</Item>
          </Operations>
        </WorkPermissions>
      </Value>
    </Item>
  </Permissions>
</Policy>