替换存储在 SQL Server 数据库列中的 XML 中的节点名称

2021-10-01 00:00:00 xml sql replace sql-server

我想知道如何替换存储在 SQL Server 数据库中的 xml 中的子节点名称

I'd like to know how I can replace a child node name in a xml that I stored in my SQL Server database

示例 XML

<CompanyStatus>
 <ProductionServers>
  <ProductionServer>
    <Patch>0</Patch>
    <Status>Green</Status>
    <Test_Node>Yes</Test_Node>
 </ProductionServers>
  </ProductionServer>
</CompanyStatus>

我将如何将其更改为以下内容:

How would I change that to the following:

<CompanyStatus>
 <ProductionServers>
  <ProductionServer>
    <Patch>0</Patch>
    <Status>Green</Status>
    <Live_Node>Yes</Live_Node>
 </ProductionServers>
  </ProductionServer>
</CompanyStatus>

基本上唯一的变化是 被重命名为 但值是相同的.

Where essentially the only change is <Test_Node> is renamed to <Live_Node> but the value is the same.

有没有简单的方法可以做到这一点?

Is there a simple way to do this?

我的数据库中有大约 1000 条记录

I have about 1000 records in my database

推荐答案

这是我的建议

  • 使用属性保存
  • 容忍元素的位置(只要这个元素是唯一的)

检查一下:

DECLARE @xml XML=
N'<CompanyStatus>
 <ProductionServers>
  <ProductionServer>
    <Patch>0</Patch>
    <Status>Green</Status>
    <Test_Node a="x" b="y" c="z">Yes</Test_Node>
 </ProductionServer>
  </ProductionServers>
</CompanyStatus>';

--这将创建带有新元素名称 及其所有属性(如果有):

--This will create the <Test_Node> with all its attributes (if there are any) with the new element name <Live_Node>:

DECLARE @NewNode XML=
    (
     SELECT @xml.query(N'let $nd:=(//*[local-name()="Test_Node"])[1]
                         return
                         <Live_Node> {$nd/@*}
                         {$nd/text()}
                         </Live_Node>
                        ')
    );

--这将首先在原始之后直接插入"@NewNode",并将删除原始:

--this will first insert the "@NewNode" directly after the original, and will remove the original:

SET @xml.modify(N'insert sql:variable("@NewNode") after (//*[local-name()="Test_Node"])[1]');
SET @xml.modify(N'delete (//*[local-name()="Test_Node"])[1]');

SELECT @xml;

结果

<CompanyStatus>
  <ProductionServers>
    <ProductionServer>
      <Patch>0</Patch>
      <Status>Green</Status>
      <Live_Node a="x" b="y" c="z">Yes</Live_Node>
    </ProductionServer>
  </ProductionServers>
</CompanyStatus>

更新:与使用可更新 CTE 的表格数据相同:

DECLARE @xmlTable TABLE (YourXml XML);
INSERT INTO @xmlTable VALUES
(--Test_Node has got attributes
N'<CompanyStatus>
 <ProductionServers>
  <ProductionServer>
    <Patch>0</Patch>
    <Status>Green</Status>
    <Test_Node a="x" b="y" c="z">Yes</Test_Node>
 </ProductionServer>
  </ProductionServers>
</CompanyStatus>'
)
,( --different position, no attributes
N'<CompanyStatus>
 <ProductionServers>
    <Test_Node>Yes</Test_Node>
  <ProductionServer>
    <Patch>0</Patch>
    <Status>Green</Status>
 </ProductionServer>
  </ProductionServers>
</CompanyStatus>'
)
,( --No test node at all
N'<CompanyStatus>
 <ProductionServers>
  <ProductionServer>
    <Patch>0</Patch>
    <Status>Green</Status>
 </ProductionServer>
  </ProductionServers>
</CompanyStatus>'
);

--可更新的 CTE 返回原始节点和新节点.这可以一次性更新:

--the updateable CTE returns the original and the new node. This can be updated in one go:

WITH ReadNode AS
(
    SELECT t.YourXml.query(N'let $nd:=(//*[local-name()="Test_Node"])[1]
                        return
                        <Live_Node> {$nd/@*}
                        {$nd/text()}
                        </Live_Node>
                    ') AS NewNode
         ,t.YourXml AS Original
    FROM @xmlTable AS t
)
UPDATE ReadNode SET Original.modify(N'insert sql:column("NewNode") after (//*[local-name()="Test_Node"])[1]');

UPDATE @xmlTable SET YourXml.modify(N'delete (//*[local-name()="Test_Node"])[1]');

SELECT *
FROM @xmlTable 

相关文章