【问题标题】:Update XML with value from another (non-xml) column in T-SQL使用 T-SQL 中另一个(非 xml)列的值更新 XML
【发布时间】:2017-02-12 01:49:42
【问题描述】:

我有一个表,其中包含两个 NUMERIC 类型的字段和一个 XML 类型的字段。这是一个粗略的示例:

CREATE TABLE books (
        ID INT NOT NULL,
        price NUMERIC(4,2),
        discount NUMERIC(2,2),
        book XML
);

XML 值看起来像,比如说,

<?xml version="1.0" encoding="UTF-8"?>
<book>
    <title>Harry Potter</title>
    <author>J K Rowling</author>
    <Store>
        <Name>Burke and Burkins</Name>
        <Address>Some St, Somewhere, Some City</Address>
    </Store>
</book>

现在我的问题是,使用xml.modify(),如何在Store 下添加两个xpath,价格和折扣分别来自books.pricebooks.discount

<?xml version="1.0" encoding="UTF-8"?>
<book>
    <title>Harry Potter</title>
    <author>J K Rowling</author>
    <Store>
        <Name>Burke and Burkins</Name>
        <Address>Some St, Somewhere, Some City</Address>
        <Price>value from books.price from the same row</Price>
        <Discount>value from books.discount from the same row</Discount>
    </Store>
</book>

这是一个粗略的例子,所以请不要担心 XML 数据的来源。假设 book 列已经存在 XML 数据。

我知道如何用静态值更新表格,

UPDATE books
SET book.modify('insert <Price>10.99</Price><Discount>20.00</Discount> after (/book/Store/Address)[1]')

这里不考虑性能。

【问题讨论】:

    标签: sql sql-server xml tsql dml


    【解决方案1】:

    不可能在一个语句中进行两次修改。

    在这种情况下,您可能会先将这两个值组合起来,然后一次插入,从而解决这个问题。

    我使用可更新的 CTE 来实现:

    CREATE TABLE books (
            ID INT NOT NULL,
            price NUMERIC(4,2),
            discount NUMERIC(2,2),
            book XML
    );
    

    --用数据填表

    INSERT INTO books VALUES(1,10.5,.5,
    '<book>
        <title>Harry Potter</title>
        <author>J K Rowling</author>
        <Store>
            <Name>Burke and Burkins</Name>
            <Address>Some St, Somewhere, Some City</Address>
        </Store>
    </book>');
    

    --这是实际的查询

    WITH CTE AS
    (
        SELECT *
              ,(SELECT price AS Price,discount AS Discount FOR XML PATH(''),TYPE) AS XmlNode 
        FROM books
    )
    UPDATE CTE SET book.modify('insert sql:column("XmlNode") after (/book/Store/Address)[1]');
    

    --检查结果

    SELECT *
    FROM books;
    

    --清理(认真对待真实约会!

    GO
    --DROP TABLE books;
    

    一个提示

    您的 XML 列,如果它真的是 XML,那么肯定会! - 不包含以&lt;?xml version="1.0" encoding="UTF-8"?&gt; 开头的 XML。内部编码始终是 unicode(ucs-2,几乎是 utf-16)并且无法更改。如果你传入一个声明,它要么被省略,要么你会得到一个错误。

    更新

    另一种方法是先读取 XML 的值,然后重新构建它:

    WITH CTE AS
    (
        SELECT *
              ,(SELECT b.value('title[1]','nvarchar(max)') AS [title]
                      ,b.value('author[1]','nvarchar(max)') AS [author]
                      ,b.value('(Store/Name)[1]','nvarchar(max)') AS [Store/Name]
                      ,b.value('(Store/Address)[1]','nvarchar(max)') AS [Store/Address]
                      ,price AS [Store/Price]
                      ,discount AS [Store/Discount]
                FROM book.nodes('book') AS A(b)
                FOR XML PATH('book'),TYPE
                ) AS bookNew
        FROM books
    )
    UPDATE CTE SET book=bookNew;
    

    【讨论】:

    • 你说得对,我的 XML 中没有 。我从自动添加该行的编辑器中复制了它。我会尝试你的解决方案,让你知道它是如何进行的。实际上,它是一个更大的 XML,需要添加大约 20 个字段:)。我会为您对问题的深入研究给予支持。谢谢。
    • 第一个解决方案适用于我的情况,因为我想要插入的所有节点都在同一个父节点(存储)下。必须有另一个使用 sql:variable 的解决方案,但我找不到任何可以让我插入多个值的解决方案。所以将此标记为答案。谢谢。
    猜你喜欢
    • 2018-07-31
    • 1970-01-01
    • 1970-01-01
    • 2011-07-17
    • 2017-01-03
    • 1970-01-01
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多