我有一个XML字符串,如下所示
<Message>
<Result>A</Result>
<Note>AA</Note>
<Note>AAA</Note>
<Note>AAAA</Note>
<Result>B</Result>
<Note>BB</Note>
<Note>BBB</Note>
<Note>BBB</Note>
</Message>
我想使用SQL选择每个Note
节点的3个Result
节点,并将它们相互附加。我是怎么做到的?
For Result A -> AA+AAA+AAAA
For Result B -> BB+BBB+BBBB
答案 0 :(得分:1)
假设您有一个如下所示的XML:
<Item Result="A">
<Note>AA</Note>
<Note>AAA</Note>
<Note>AAAA</Note>
</Item>
<Item Result="B">
<Note>BB</Note>
<Note>BBB</Note>
<Note>BBB</Note>
</Item>
然后通过粉碎Item
并使用for xml path('')
连接Note
节点,可以轻松生成所需的结果。
select T.X.value('@Result', 'nvarchar(100)') as Result,
(
select T2.X.value('text()[1]', 'nvarchar(100)')+' '
from T.X.nodes('Note') T2(X)
for xml path(''), type
).value('text()[1]', 'nvarchar(100)') as Note
from @XML.nodes('/Item') as T(X);
您可以使用此查询将XML重建为所需的格式。
set @XML = @XML.query('for $n in /Message/Result
return element Item {
attribute Result{$n/text()},
/Message/Note[. >> $n][position() < 4]
}');
另一种选择是在Message/*
上粉碎并使用CTE中的row_number()
枚举所有行。在主查询和使用for xml path('')
的子查询中使用CTE将字符串与使用生成的数字的连接连接起来。
with C as
(
select T.X.value('text()[1]', 'nvarchar(100)') as Value,
T.X.value('local-name(.)', 'nvarchar(100)') as NodeName,
row_number() over(order by T.X)as rn
from @XML.nodes('/Message/*') as T(X)
)
select C1.Value as Result,
(
select C2.Value+' '
from C as C2
where C2.rn > C1.rn and
C2.rn < C1.rn + 4
for xml path(''), type
).value('text()[1]', 'nvarchar(100)') as Note
from C as C1
where C1.NodeName = 'Result'
<子>
注意:使用row_number()
枚举XML文档中的节点的技术依赖于SQL Server分析XML的内部实现的知识。 Microsoft未记录该行为。 Adam Machanic在此发表了博文:Uniquely Identifying XML Nodes with DENSE_RANK
子>