当前位置: 首页 > 知识库问答 >
问题:

T-SQL XML:如果有多个节点具有相同的名称,如何更新一个节点中的值?

萧焱
2023-03-14

我刚刚开始学习如何使用XML数据格式,并且已经在更新一些数据上陷入了困境。我真的,真的很感谢有人帮我解决这个问题,因为我完全不知道怎么处理这样的问题。

生成一些示例数据的代码

IF OBJECT_iD('tempdb..#beforeXML') is NOT NULL 
    DROP TABLE #beforeXML 

CREATE TABLE #beforeXML 
(
    ID int NOT NULL,    
    SomeXMLData XML NOT NULL
)

INSERT INTO #beforeXML (ID, SomeXMLData)
VALUES 
    (1, '<Parameters><Parameter><Key>ABC</Key><Value>1, 2, 4</Value></Parameter><Parameter><Key>XYZ</Key><Value>A</Value></Parameter></Parameters>'),
    (2, '<Parameters><Parameter><Key>KLM</Key><Value>true</Value></Parameter><Parameter><Key>ABC</Key><Value>1, 2, 4, 5</Value></Parameter></Parameters>'),
    (3, '<Parameters><Parameter><Key>KLM</Key><Value>false</Value></Parameter><Parameter><Key>ABC</Key><Value>1, 2, 3, 6</Value></Parameter><Parameter><Key>XYZ</Key><Value>A, C</Value></Parameter></Parameters>'),
    (4, '<Parameters><Parameter><Key>XYZ</Key><Value>A</Value></Parameter><Parameter><Key>ABC</Key><Value>1, 2, 3, 5</Value></Parameter></Parameters>'),
    (5, '<Parameters><Parameter><Key>XYZ</Key><Value>B</Value></Parameter><Parameter><Key>KLM</Key><Value>true</Value></Parameter></Parameters>')

SELECT * FROM #beforeXML

现在困难的部分来了...

我需要更新“value”节点的值,其中“key”节点的值=“abc”在同一个“parameter”节点中。

正如您所看到的,我的xml中有几个“参数”节点,这些节点没有我可以用来区分它们和确定应该更新哪些节点的特定顺序或属性。有些行没有这样的节点,有些行在“value”节点中已经有了数字3或/和5,所以我只需要在缺少一个或两个(3或/和5)的情况下添加。

我想得到的结果是:

IF OBJECT_iD('tempdb..#afterXML') IS NOT NULL 
    DROP TABLE #afterXML 

CREATE TABLE #afterXML 
(
    ID int NOT NULL,    
    SomeXMLData XML NOT NULL
)

INSERT INTO #afterXML (ID, SomeXMLData)
VALUES 
    -- added both 3, 5
    (1, '<Parameters><Parameter><Key>ABC</Key><Value>1, 2, 3, 4, 5</Value></Parameter><Parameter><Key>XYZ</Key><Value>A</Value></Parameter></Parameters>'),  
    -- added only 3
    (2, '<Parameters><Parameter><Key>KLM</Key><Value>true</Value></Parameter>
<Parameter><Key>ABC</Key><Value>1, 2, 3, 4, 5</Value></Parameter></Parameters>'),    
    -- added only 5
    (3, '<Parameters><Parameter><Key>KLM</Key><Value>false</Value></Parameter><Parameter><Key>ABC</Key><Value>1, 2, 3, 5, 6</Value></Parameter><Parameter><Key>XYZ</Key><Value>A, C</Value></Parameter></Parameters>'),
    -- no change
    (4, '<Parameters><Parameter><Key>XYZ</Key><Value>A</Value></Parameter><Parameter><Key>ABC</Key><Value>1, 2, 3, 5</Value></Parameter></Parameters>'), 
    -- no change
    (5, '<Parameters><Parameter><Key>XYZ</Key><Value>B</Value></Parameter><Parameter><Key>KLM</Key><Value>true</Value></Parameter></Parameters>')  

SELECT * FROM #afterXML
IF OBJECT_iD('tempdb..#temp_table') IS NOT NULL 
    DROP TABLE #temp_table

CREATE TABLE #temp_table 
(
    ID int NOT NULL,    
    NewSetOfValues varchar(100) NOT NULL
)

INSERT INTO #temp_table (ID, NewSetOfValues)
VALUES 
    (1, '1, 2, 3, 4, 5'),
    (2, '1, 2, 3, 4, 5'),
    (3, '1, 2, 3, 5, 6')
 
SELECT * FROM #temp_table

事先谢谢你的帮助。

共有1个答案

越高峻
2023-03-14

诚然,这并不是按照数字的顺序对XML字符串进行排序,但您应该能够根据需要对其进行处理:

update b
-- .modify is a special function that modifies XML in place
set SomeXMLData.modify('
    replace value of
    (/Parameters/Parameter[Key[text()="ABC"]]/Value/text())[1]
    with
    concat (
        (/Parameters/Parameter[Key[text()="ABC"]]/Value/text())[1],
        if ((/Parameters/Parameter[Key[text()="ABC"]]/Value[contains(text()[1], "3")])[1] ) then "" else ", 3" ,
        if ((/Parameters/Parameter[Key[text()="ABC"]]/Value[contains(text()[1], "5")])[1] ) then "" else ", 5" 
    )')
from @beforeXML b;

其工作方式如下:

  1. 我们搜索XML节点,从根/开始,降序参数,然后降序参数但此节点必须有一个子节点key,该子节点具有text()=“abc”,然后降序/value/text())并取第一个[1]节点。
  2. 将此值替换为现有值的串联,并:
  3. 如果value节点匹配[contains(text()[1],“3”)])[1])则不匹配,否则添加“,3”
  4. 如果value节点匹配[contains(text()[1],“5”)])[1])则不匹配,否则添加“,5”
|SomeDataXML|
----
|<Parameters><Parameter><Key>ABC</Key><Value>1, 2, 4, 3, 5</Value></Parameter><Parameter><Key>XYZ</Key><Value>A</Value></Parameter></Parameters>|
|<Parameters><Parameter><Key>KLM</Key><Value>true</Value></Parameter><Parameter><Key>ABC</Key><Value>1, 2, 4, 5, 3</Value></Parameter></Parameters>|
|<Parameters><Parameter><Key>KLM</Key><Value>false</Value></Parameter><Parameter><Key>ABC</Key><Value>1, 2, 3, 6, 5</Value></Parameter><Parameter><Key>XYZ</Key><Value>A, C</Value></Parameter></Parameters>|
|<Parameters><Parameter><Key>XYZ</Key><Value>A</Value></Parameter><Parameter><Key>ABC</Key><Value>1, 2, 3, 5</Value></Parameter></Parameters>|
|<Parameters><Parameter><Key>XYZ</Key><Value>B</Value></Parameter><Parameter><Key>KLM</Key><Value>true</Value></Parameter></Parameters>|
 类似资料:
  • 但它没有提供所需的产出。它给出的输出像 我是XSL的新手。有谁能帮我解决这个问题吗?

  • 我是 D3 的新手。因此,我正在尝试呈现一个图形,其中两个或多个孩子可以具有相同的父级。我想知道如何使链接再次定向到同一节点?我有断开的链接.. 任何帮助都是巨大的。 这是我的代码...

  • 我已经实现了一个TreeModel来调整存量数据模型,以便将其可视化为JTree。我遇到了一个问题,节点有多个相同的子(叶)节点。例如,考虑一个JTree,它的叶节点是Strings。每当父节点包含具有相同String值的子节点时,就会出现问题。这些叶节点的TreePath是相同的,作为Strings,equals()返回true。留档明确地调用这个: JTree及其相关类广泛使用TreePath

  • firebase中我的数据库截图 这里我有一个叫做产品的节点。在那里,我有许多子节点。所有这些节点都有一个共同的值叫做产品库存。我需要更新产品内部所有节点的产品库存值。我如何在android Studio(Java)中做到这一点,因为我正在开发一个购物应用程序?需要帮助。 流程是:用户将产品添加到购物车。在购物车里,我有ordernow按钮。因此,当用户现在单击order时,应该从products

  • 我正在尝试做一个使用组合键的场景。我想有更多的公钥,这样我就可以用其中任何一个密钥来签署一个txn。 该场景的参考如下:https://docs.corda.net/api/kotlin/corda/net.corda.core.crypto/-composite-key/index.html 根据我的理解,deployNodes任务使用单个公钥生成节点。如果我偏离了轨道,请纠正我。