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

使用SQL Server上另一个XML中的节点更新XML列,sql,sql-server,xml,sql-update,Sql,Sql Server,Xml,Sql Update,我有两个具有1-M关系的表,都包含XML列。我必须从第一个表的XML节点的另一个节点更新第二个表列中的XML。在与语法斗争以使其工作后,我终于能够使其工作。然而,它仍然不起作用。我在messages选项卡中看到行被更新,但当我从第二个表中选择值时,没有更新任何内容。以下是我的TSQL代码示例: DECLARE @Table1 TABLE ( Id BIGINT PRIMARY KEY ,Document XML ,NewValue NVARCHAR(max) )

我有两个具有1-M关系的表,都包含XML列。我必须从第一个表的XML节点的另一个节点更新第二个表列中的XML。在与语法斗争以使其工作后,我终于能够使其工作。然而,它仍然不起作用。我在messages选项卡中看到行被更新,但当我从第二个表中选择值时,没有更新任何内容。以下是我的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。另外,我在select期间没有从父表获取子节点,而是在更新期间尝试获取值

更新

下面是更新后的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
DECLARE@Table1表(
Id BIGINT主键
,文档XML
,新值NVARCHAR(最大值)
)
插入@Table1(
身份证件
,文件
)
价值观(
1.
“标题1标题1”
)
插入@Table1(
身份证件
,文件
)
价值观(
2.
,“标题2标题2”
)
插入@Table1(
身份证件
,文件
)
价值观(
3.
“标题3领导人3”
)
插入@Table1(
身份证件
,文件
)
价值观(
4.
“标题4领导4”
)
更新@Table1
SET NewValue=Document.value('(/root/metadata/title)[1],'nvarchar(max)'
声明@Table2表(
Id BIGINT主键
,ParentId BIGINT
,原始XML
,ModifiedXml
,值类型NVARCHAR(255)
)
插入@Table2
价值观(
1.
1.
“旧标题1”
“旧标题1”
“网络”
)
插入@Table2
价值观(
2.
3.
“旧标题3”
“旧标题3”
“html”
)
打印“更新前”
更新sm
SET ModifiedXml.modify((//url/loc/text())[1]的值替换为sql:column(“NewValue”))
来自@Table2 sm
a.Id=sm.ParentId上的表1 a的内部联接
其中sm.ValueType='web';
更新sm
SET ModifiedXml.modify((/html/url/text())[1]的值替换为sql:column(“NewValue”))
来自@Table2 sm
a.Id=sm.ParentId上的表1 a的内部联接
其中sm.ValueType='html';
打印“更新后”
挑选*
来自@Table2

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

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

然而,这仍然不能解释为什么我得到了“x行数更新”,而实际数据没有变化。而且,并非每行都有名称空间。这意味着应该更新没有名称空间的行。无论如何,感谢@GriGrim和@Roman Pekar的输入。

FYI,我还尝试用文字而不是列替换该值。我得到了同样的结果。在message选项卡中,我看到一些行已更新,但实际值没有更改。您正在尝试获取
a.Document.value(“(/root/metadata/name)[1]”,'nvarchar(500)”)
,而在您的示例中没有“name”节点。您还试图替换
(//url/loc/text())[1]
的值,而“url”节点位于第一级,而不是第二级。写一个斜杠:
(/url/loc/text())[1]
。此时节点的名称并不重要。我没有发布整个架构<代码>/只是另一次尝试。我原来有
/url/loc/text()
,但这不起作用。我还尝试了
//loc/text()
,但也没有成功。很难重现您的错误,请在sqlfiddle.com上创建一个测试,包含ParentTable、childTable和一些数据。我已更新了问题。第二部分似乎正在发挥作用。我会检查我的XPath,看看我是否做错了什么。