SQL Server - 仅使用 .modify() 合并两个 XML

SQL Server - merge two XML using only .modify()(SQL Server - 仅使用 .modify() 合并两个 XML)
本文介绍了SQL Server - 仅使用 .modify() 合并两个 XML的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有:

CREATE TABLE #Users(id INT PRIMARY KEY, name VARCHAR(100), suggestions XML);

INSERT INTO #Users(id, name, suggestions)
SELECT 1, 'Bob', N'<Products>
                     <Product id="1" score="1"/>
                     <Product id="2" score="5"/>
                     <Product id="3" score="4"/>
                   </Products>'
UNION ALL
SELECT 2, 'Jimmy', N'<Products>
                       <Product id="6" score="3"/>
                     </Products>';

DECLARE @userId INT = 1,
        @suggestions XML = N'<Products>
                              <Product id="2" score="5"/>
                              <Product id="3" score="2"/>
                              <Product id="7" score="1" />
                             </Products>';

游乐场

现在我想根据 id 属性合并 2 个 XML:

Now I want to merge 2 XMLs based on id attribute:

id = 1 的用户的最终结果:

Final result for user with id = 1:

<Products>
  <Product id="1" score="1"/> -- nothing changed (but not exists in @suggestions)
  <Product id="2" score="5"/> -- nothing changed (but exists in @suggestions)
  <Product id="3" score="2"/> -- update score to 2
  <Product id="7" score="1"/> -- insert new element
</Products>

请注意,它不是组合 2 个 XML,而是upsert"操作.

Please note that it is not combining 2 XMLs but "upsert" operation.

备注:

  • 我知道这种模式违反了数据库规范化,规范化是可行的方法(但在这种情况下不是)
  • 我知道使用派生表的解决方案,.nodes().value() 函数首先解析两个 XML,然后合并并写回
  • I know that this kind of schema violates database normalization and normalizing it is the way to go (but not in this case)
  • I know solution that utilize derived tables, .nodes() and .value() functions first to parse both XML, then merge and write back

我正在寻找的是 XPath/XQuery 表达式,它将合并到一个语句中(无派生表/动态 sql*):

I am searching for is XPath/XQuery expression that will merge it in one statement (no derived tables/dynamic-sql*):

* 如果绝对需要,可以使用动态 SQL,但我想避免使用.

UPDATE #Users
SET suggestions.modify(... sql:variable("@suggestions") ...); --changes only here
WHERE id = @userId;


/* replace ... for ... where ... with sql:variable */

推荐答案

尝试了一段时间后,我认为这是不可能的...

After trying around a while I think this is not possible...

这里有类似的问题:XQuery 在单个 SQL 更新命令中添加或替换属性

.modify(insert Expression1 ... ) 不允许在通过 @sql:variable() 传入的 XML 获取数据code> 或 sql:column()

The .modify(insert Expression1 ... ) does not allow to get data within an XML passed in via @sql:variable() or sql:column()

在此处阅读:https://msdn.microsoft.com/en-us/library/ms175466.aspx 在 Expression1 -> "常量 XML 或独立的 sql:column/sql:variable 或 XQuery(到同一实例)

Read here: https://msdn.microsoft.com/en-us/library/ms175466.aspx at Expression1 -> "constant XML or stand alone sql:column / sql:variable or XQuery (to the same instance)

DECLARE @xml1 XML= --the existing XML
'<Products>
  <Product id="1" score="1" />
  <Product id="2" score="5" />
  <Product id="3" score="4" />
</Products>';

DECLARE @xml2 XML= --the XML with new or changed data
'<Products>
  <Product id="2" score="5" />
  <Product id="3" score="2" />
  <Product id="7" score="1" />
</Products>';

SET @xml1.modify('insert sql:variable("@xml2") as first into /Products[1]');

SELECT @xml1;

/* The full node is inserted!
Without any kind of preparation there is NO CHANCE to get the inner nodes only

<Products>
  <Products>
    <Product id="2" score="5" />
    <Product id="3" score="2" />
    <Product id="7" score="1" />
  </Products>
  <Product id="1" score="1" />
  <Product id="2" score="5" />
  <Product id="3" score="4" />
</Products>
*/

您可以这样声明第二个 XML:

You might declare the second XML as such:

DECLARE @xml2 XML= --the XML with new or changed data
'<Product id="2" score="5" />
 <Product id="3" score="2" />
 <Product id="7" score="1" />';

但是您将没有机会使用 id 的值作为 XQuery 过滤器

But than you'll have no chance to use the id's value as XQuery filter

SET @xml1.modify('insert sql:variable("@xml2") as first into /Products[**How should one filter here?**]');

最后但并非最不重要的一点,我认为没有机会在 .modify() 的一次调用中组合两个不同的 XML_DML 语句.

And last but not least I think there is no chance to combine two different XML_DML statements within one call of .modify().

我唯一的想法就是这个,但它行不通.IF 似乎只能在一个表达式中使用,但不能区分两个执行路径

The only idea I had was this, but it doesn't work. IF seems to be usable only within an Expression, but not two distinguish between two execution paths

SET @xml1.modify('if (1=1) then
                     insert sql:variable("@xml2") as first into /Products[1]
                  else
                     replace value of /Products[1]/Product[@id=1][1]/@score with 100');

所以我的结论是:不,这是不可能的...

So my conclusion: No, this is not possible...

我在这里提供的解决方案 https://stackoverflow.com/a/35060150/5089204 在第二部分(如果你想‘合并’两本书结构")将是我解决这个问题的方法.

The solution I provided here https://stackoverflow.com/a/35060150/5089204 in the second section ("If you want to 'merge' two Books-structures") would be my way to solve this.

这篇关于SQL Server - 仅使用 .modify() 合并两个 XML的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Execute complex raw SQL query in EF6(在EF6中执行复杂的原始SQL查询)
Hibernate reactive No Vert.x context active in aws rds(AWS RDS中的休眠反应性非Vert.x上下文处于活动状态)
Bulk insert with mysql2 and NodeJs throws 500(使用mysql2和NodeJS的大容量插入抛出500)
Flask + PyMySQL giving error no attribute #39;settimeout#39;(FlASK+PyMySQL给出错误,没有属性#39;setTimeout#39;)
auto_increment column for a group of rows?(一组行的AUTO_INCREMENT列?)
Sort by ID DESC(按ID代码排序)