sql - 使用 SQL Server 上另一个 XML 的节点更新 XML 列

标签 sql sql-server xml sql-update

我有两个具有 1-M 关系的表,都包含 XML 列。我必须从第一个表的 XML 节点的另一个节点更新第二个表的列中的 XML。在努力使用语法使其工作之后,我终于能够让它工作了。但是,它仍然无法正常工作。我看到消息选项卡中的行得到更新,但是当我从第二个表中选择值时,没有任何更新。这是我的 TSQL 代码示例:

DECLARE @Table1 TABLE (
    Id BIGINT PRIMARY KEY
    ,Document XML
    ,NewValue NVARCHAR(max)
    )

INSERT INTO @Table1
SELECT TOP 10 a.Id
    ,a.Document
    ,a.Document.value('(/root/metadata/name)[1]', 'nvarchar(500)') + 'blahblah'
FROM dbo.ParentTable a
ORDER BY a.Id DESC

DECLARE @Table2 TABLE (
    Id BIGINT PRIMARY KEY
    ,ParentId BIGINT
    ,OriginalXml XML
    ,ModifiedXml XML
    ,ValueType NVARCHAR(255)
    )

INSERT INTO @Table2
SELECT sm.Id
    ,sm.ParentId
    ,sm.MapXml
    ,sm.MapXml
    ,sm.ValueType
FROM dbo.ChildTable sm

PRINT 'before update'

UPDATE sm
SET ModifiedXml.modify('replace value of (//url/loc/text())[1] with sql:column("NewValue")')
FROM @Table2 sm
INNER JOIN @Table1 a ON a.Id = sm.ParentId
WHERE sm.ValueType = 'web';

UPDATE sm
SET ModifiedXml.modify('replace value of (/html/url/text())[1] with sql:column("NewValue")')
FROM @Table2 sm
INNER JOIN @Table1 a ON a.Id = sm.ParentId
WHERE sm.ValueType = 'html';

PRINT 'after update'

SELECT *
FROM @Table2

如果不清楚,这里是父表的 XML 架构:

<root>
    <metadata>
        <title></title>
        <header></header>
        <nodeN></nodeN>
    </metadata>
</root>

这里有两种可能的子表模式:

<url>
    <loc>somevalue</loc>
</url>

<html>
    <url>somevlaue</url>
</html>

我之前遇到的问题是我将修改后的 XML 列声明为 XML。此外,在选择期间我没有从父表中获取子节点,而是尝试在更新期间获取值。

更新

这是更新后的 SQL。由于某种原因,这正在起作用。我没有发布原始 XML 模式的唯一原因是它们太长了。我将仔细检查原始 TSQL 中的 XPath。

DECLARE @Table1 TABLE (
    Id BIGINT PRIMARY KEY
    ,Document XML
    ,NewValue NVARCHAR(max)
    )

INSERT INTO @Table1 (
    Id
    ,Document
    )
VALUES (
    1
    ,'<root><metadata><title>title 1</title><header>header 1</header></metadata></root>'
    )

INSERT INTO @Table1 (
    Id
    ,Document
    )
VALUES (
    2
    ,'<root><metadata><title>title 2</title><header>header 2</header></metadata></root>'
    )

INSERT INTO @Table1 (
    Id
    ,Document
    )
VALUES (
    3
    ,'<root><metadata><title>title 3</title><header>header 3</header></metadata></root>'
    )

INSERT INTO @Table1 (
    Id
    ,Document
    )
VALUES (
    4
    ,'<root><metadata><title>title 4</title><header>header 4</header></metadata></root>'
    )

UPDATE @Table1
SET NewValue = Document.value('(/root/metadata/title)[1]', 'nvarchar(max)')

DECLARE @Table2 TABLE (
    Id BIGINT PRIMARY KEY
    ,ParentId BIGINT
    ,OriginalXml XML
    ,ModifiedXml XML
    ,ValueType NVARCHAR(255)
    )

INSERT INTO @Table2
VALUES (
    1
    ,1
    ,'<url><loc>old title 1</loc></url>'
    ,'<url><loc>old title 1</loc></url>'
    ,'web'
    )

INSERT INTO @Table2
VALUES (
    2
    ,3
    ,'<html><url>old title 3</url></html>'
    ,'<html><url>old title 3</url></html>'
    ,'html'
    )

PRINT 'before update'

UPDATE sm
SET ModifiedXml.modify('replace value of (//url/loc/text())[1] with sql:column("NewValue")')
FROM @Table2 sm
INNER JOIN @Table1 a ON a.Id = sm.ParentId
WHERE sm.ValueType = 'web';

UPDATE sm
SET ModifiedXml.modify('replace value of (/html/url/text())[1] with sql:column("NewValue")')
FROM @Table2 sm
INNER JOIN @Table1 a ON a.Id = sm.ParentId
WHERE sm.ValueType = 'html';

PRINT 'after update'

SELECT *
FROM @Table2

最佳答案

不完全是一个答案,因为我的代码一开始就没有问题。我终于能够看到子表 XML 列的 XML 模式,并且在某些行中,它在 XML 中有一些 namespace 。添加命名空间后,我能够更新数据。

WITH XMLNAMESPACES (DEFAULT 'http://www.sitemaps.org/schemas/sitemap/0.9') 
UPDATE ...

但是,这仍然不能解释为什么我得到“更新了 x 行”但实际数据没有变化。此外,并非每一行都有 namespace 。这意味着没有命名空间的行应该已经更新。无论如何,感谢@GriGrim 和@Roman Pekar 的投入。

关于sql - 使用 SQL Server 上另一个 XML 的节点更新 XML 列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18303224/

相关文章:

mysql - 日期列表和另一个表的交叉连接

sql - 我的案例有什么问题?

sql - 如何对连续范围进行分组

python - 如何在odoo中通过many2one字段设置默认值?

c# - VS2008 - 从 Web 服务反序列化时出错

java - 使用 ResideMenu lib 时删除菜单项

php - 如何防止 PHP 中的 SQL 注入(inject)?

SQL 数据规范化更改示例

sql-server - 如何将图像插入到sql server数据库中?

sql-server - 如何以与 SQL Server 中相同的顺序将列从 SQL 导入 Excel?