我在SQL Server 2008中有一个表,它将XML数据存储在XML列中。典型的XML片段是:
<validation>
<Field1 author="56234" date="20120101" />
<Field2 author="23232" date="20120101" />
[...etc...]
</validation>
我正在尝试解决的问题 - 我无法看到如何做 - 是通过INNER JOIN选择此数据到另一个表并修改结果集中的XML数据,即我得到的这样:
<validation>
<Field1 author="56234" date="20120101" authorFullName="Bob Smith" />
<Field2 author="23232" date="20120101" authorFullName="Jane Hill" />
[...etc...]
</validation>
现在我知道我可以做CROSS APPLY
直接将XML数据拉入记录集和内连接 - 例如:
select xmldata.a, people.personname
from xmldata
cross apply xmldata.x.nodes('/validation/node()') vdata(fielddata)
inner join people
on people.personid = vdata.fielddata.value('@author','NVARCHAR(20)')
但我真正想做的是返回原始XML但添加了新属性,将people.PersonName映射到新的@authorFullName属性。
我无法弄清楚语法(或者即使它确实可行)。我假设我cross apply
与modify
进行insert attribute
- 基于
select xmldata.a, xmldata.x
from xmldata
cross apply xmldata.x.modify('insert attribute authorFullName {sql:column("people.personfullname")} into /validation/node()')
inner join people
on people.personid = [...what goes here?...]
但是正确的语法正在逃避我。我越来越认为这是不可能的,我最好在两个查询中执行此操作并将结果合并到非SQL业务逻辑中。
答案 0 :(得分:1)
您不能在select语句中使用modify
。
来自modify() Method (xml Data Type)
xml数据类型的modify()方法只能在SET中使用 UPDATE语句的子句。
我认为你有两种选择。
for xml path
以您希望的方式重建XML文档,并在适当的位置插入人名。 set @XML.modify(insert...
插入人名。如果你选择第二个选项,你必须使用while循环,因为insert (XML DML)中的expression2必须是一个单独的节点。
选项2的代码看起来像这样。
declare @XML xml
declare @C int
declare @PersonName varchar(50)
declare @PersonID int
-- Store your XML in a XML variable
set @XML =
'<validation>
<Field1 author="56234" date="20120101" />
<Field2 author="23232" date="20120101" />
</validation>'
-- Get number of nodes to be modified
set @C = @XML.value('count(/validation/*)', 'int')
-- For each node
while @C > 0
begin
-- Get person id from XML
set @PersonID = @XML.value('(/validation/*[sql:variable("@C")]/@author)[1]', 'int')
-- Get person name
select @PersonName = personname
from people
where personid = @PersonID
if @@rowcount = 1
begin
-- add person name to XML
set @XML.modify('insert attribute authorFullName {sql:variable("@PersonName")}
into (/validation/*[sql:variable("@C")])[1]')
end
-- next node
set @C = @C - 1
end