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

时间:2016-10-04 01:59:18

标签: sql sql-server xml tsql dml

我有一个包含两个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 book列已经存在XML数据。

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

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

此处不考虑性能。

1 个答案:

答案 0 :(得分:4)

在一个陈述中不可能进行两次修改。

在这种情况下,您可以先将两个值组合起来,然后立即插入它们来解决这个问题。

我使用可更新的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,肯定会! - 不包含以<?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;