【问题标题】:SQL Server relations between two table by xml type coumn and output xml通过xmltype列和输出xml在两个表之间的SQL Server关系
【发布时间】:2016-11-16 13:48:15
【问题描述】:

我正在尝试编写查询,但尚未成功。如果可能的话,我需要一些帮助。

我有 2 张桌子,CategoryProduct

类别表格

列:Id int、ParentID int、XmlData XML

INSERT INTO Category
VALUES (1, 0,
'<category>
   <item>BMW</item>
   <item>MERCEDES</item>
   <item>AUDI</item>
   <item>WOLKSVAGEN</item>
</category>')

产品表:

Columns Id int, XmlData xml

INSERT INTO Product 
VALUES (1, '<item>
    <category id="1" />
    <name>Carburetor</name>
    <model>MDS343498</model>
    <price>$3000</price>
    <stock>123</stock>
</item>')

我想合并相关的两个 XML 列。

我想要这样的输出:

'<item>
    <category id="1">
        <item>BMW</item>
        <item>MERCEDES</item>
        <item>AUDI</item>
        <item>WOLKSVAGEN</item>
    </category>
    <name>Carburetor</name>
    <model>MDS343498</model>
    <price>$3000</price>
    <stock>123</stock>
</item>'

【问题讨论】:

    标签: sql sql-server xml xpath xquery


    【解决方案1】:

    用另一个节点替换一个节点有点棘手。以下代码将首先使用可更新的 CTE 找到合适的 category,获取其 XmlData,然后使用 CTE 到 UPDATE 产品的 XmlDatainsert 新节点.

    我们现在的问题是:类别存在两次:一次是新节点,第二次是旧节点。当我们插入 as first 时,我们可以肯定,第二次出现是要删除的:

    DECLARE @Category Table(Id int, ParentID int, XmlData XML);
    INSERT INTO @Category
    VALUES (
    1, 
    0,
    '<category>
       <item>BMW</item>
       <item>MERCEDES</item>
       <item>AUDI</item>
       <item>WOLKSVAGEN</item>
    </category>'
    );
    
    DECLARE @Product Table (Id int, XmlData xml);
    
    INSERT INTO @Product 
    VALUES (
    1,
    '<item>
        <category id="1" />
        <name>Carburetor</name>
        <model>MDS343498</model>
        <price>$3000</price>
        <stock>123</stock>
    </item>'
    );
    

    --可更新的CTE

    WITH UpdateableCTE AS
    (
        SELECT p.Id
              ,p.XmlData
              ,Cat.XmlData AS XmlToInsert
        FROM @Product AS p
        CROSS APPLY (SELECT c.XmlData FROM @Category AS c WHERE Id=p.XmlData.value('(/item/category/@id)[1]','int')) AS Cat
    )
    UPDATE UpdateableCTE
    SET XmlData.modify(N'insert sql:column("XmlToInsert") as first into (/item)[1]');
    

    --删除第二次出现

    UPDATE @Product SET XmlData.modify(N'delete /item[1]/category[2]')
    

    --XmlData中的结果:

    SELECT * FROM @Product
    
    <item>
      <category>
        <item>BMW</item>
        <item>MERCEDES</item>
        <item>AUDI</item>
        <item>WOLKSVAGEN</item>
      </category>
      <name>Carburetor</name>
      <model>MDS343498</model>
      <price>$3000</price>
      <stock>123</stock>
    </item>
    

    OT:您可能想将WOLKSVAGEN 更正为VOLKSWAGEN :-)

    UPDATE 保留属性&lt;category id="1"&gt;,在上面的方法中丢失了:

    我使用FLWOR-查询来预先组织XmlToInsert

    WITH UpdateableCTE AS
    (
        SELECT p.Id
              ,p.XmlData
              ,Cat.XmlData.query
              (
              N'<category id="{sql:column("CatId")}">
                {/category/item}
                </category>'
              ) AS XmlToInsert
        FROM @Product AS p
        CROSS APPLY (SELECT c.Id AS CatId, c.XmlData FROM @Category AS c WHERE Id=p.XmlData.value('(/item/category/@id)[1]','int')) AS Cat
    )
    UPDATE UpdateableCTE
    SET XmlData.modify(N'insert sql:column("XmlToInsert") as first into (/item)[1]');
    
    UPDATE @Product SET XmlData.modify(N'delete /item[1]/category[2]')
    
    SELECT * FROM @Product
    

    更新 2:不同的方法动态

    这样试试

    WITH CTE AS
    (
        SELECT p.Id
              ,p.XmlData
              ,Cat.XmlData.query
              (
              N'<category id="{sql:column("CatId")}">
                {/category/item}
                </category>'
              ) AS XmlToInsert
        FROM @Product AS p
        CROSS APPLY (SELECT TOP 1 c.Id AS CatId, c.XmlData FROM @Category AS c WHERE Id=p.XmlData.value('(/item/category/@id)[1]','int')) AS Cat
    )
    SELECT XmlToInsert AS [node()]
          ,XmlData.query('/item/*[local-name()!="category"]')
    FROM CTE
    FOR XML PATH('item')
    

    【讨论】:

    • 谢谢 :-),但你可以不声明。表已经存在。
    • @Uysal,这很简单...只需从 WITH ... 开始,然后将表名(@Product@Category)更改为您的实际表名。 声明的表变量只是一个mock-up来创建一个测试场景。
    • 我不想更新表上的数据,我想要动态结果。
    • @Uysal 查看我的更新 2
    • @Uysal 这个问题解决了吗?您需要进一步的帮助吗?请给我一个提示:如果这个问题得到了解决,您将非常好心,在(最佳)答案的投票计数器下方勾选接受检查。这将 1) 将此问题标记为已解决 2) 让追随者更容易找到最佳解决方案 3) 向回答者支付积分和 4) 向您支付积分。由于您自己已经越过了 15 点边界,因此您还被要求对贡献进行投票。这是说谢谢的方式。编码快乐!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多