使用 T-SQL 中另一个(非 xml)列的值更新 XML

Update XML with value from another (non-xml) column in T-SQL

我有一个 table,其中有两个 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 数据来自哪里。假设书籍列中已经存在 XML 数据。

我知道如何用静态值更新 table

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

此处不考虑性能。

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

在这种情况下,您可以通过首先组合两个值然后一次插入它们来解决这个问题。

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

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

--用数据

填充table
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,将会 - 当然! - 不包含以 <?xml version="1.0" encoding="UTF-8"?> 开头的 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;