我正在尝试从SQL Server 2008中的XML列中提取一些信息。表中的每一行都包含一个XML文档,表示一个包含多人控件的报表。每个人条目都有一个GroupStartControl,一个PersonControl,一个TextControl和一个GroupEndControl。 GroupStartControl具有Guid属性,其他3个控件具有ParentId属性,该属性与它们所属的StartControl的Guid相同。问题是控件在我们系统的前端使用此ID与启动控件匹配,但在XML中它们没有按层次分组,所以我很难从中提取每个人的PersonId和Comment信息。我尝试过使用外部和交叉应用并设法得到以下示例。
我在http://sqlfiddle.com/#!3/25d9b/1创建了一个小提琴,重现我在SSMS中面临的问题的代码如下:
DECLARE @SampleTable TABLE
(
ReportId INT,
PersonXml XML
)
INSERT @SampleTable (ReportId, PersonXml)
VALUES (1, '<Report>
<Controls>
<Control Guid="d77b7329-7974-4580-971c-d8c3fcdf5909" ControlType="GroupStartControl" />
<Control Guid="88ad2a34-89a6-46da-b62a-7b4ac4bbf68a" ParentId="d77b7329-7974-4580-971c-d8c3fcdf5909" ControlType="PersonControl">
<Fields>
<Field Label="PersonId" Value="12345" UniqueIdentifier="PersonId" />
<Field Label="Another field we do not care about" Value="" UniqueIdentifier="AnotherField" />
</Fields>
</Control>
<Control Guid="b54679d4-1cc1-4718-bec7-9f37ea00abe1" ParentId="d77b7329-7974-4580-971c-d8c3fcdf5909" ControlType="TextControl">
<Fields>
<Field Label="Comment" Value="Comments regarding person 12345" UniqueIdentifier="PersonComment" />
<Field Label="Some other field we do not need to examine" Value="" UniqueIdentifier="SomeOtherField" />
</Fields>
</Control>
<Control Guid="ec96950a-5bcc-455e-a0e4-40986f95ff37" ParentId="d77b7329-7974-4580-971c-d8c3fcdf5909" ControlType="GroupEndControl" />
<Control Guid="560a3d55-21c6-4f36-9430-f4a66d2affe3" ControlType="GroupStartControl" />
<Control Guid="acdf3332-d401-451c-aeaa-0547f752f0f0" ParentId="560a3d55-21c6-4f36-9430-f4a66d2affe3" ControlType="PersonControl">
<Fields>
<Field Label="PersonId" Value="7890" UniqueIdentifier="PersonId" />
<Field Label="Another field we do not care about" Value="" UniqueIdentifier="AnotherField" />
</Fields>
</Control>
<Control Guid="90b53f55-eb0b-498c-aa61-524e39db5634" ParentId="560a3d55-21c6-4f36-9430-f4a66d2affe3" ControlType="TextControl">
<Fields>
<Field Label="Comment" Value="Comments regarding person 7890" UniqueIdentifier="PersonComment" />
<Field Label="Some other field we do not need to examine" Value="" UniqueIdentifier="SomeOtherField" />
</Fields>
</Control>
<Control Guid="ec96950a-5bcc-455e-a0e4-40986f95ff37" ParentId="560a3d55-21c6-4f36-9430-f4a66d2affe3" ControlType="GroupEndControl" />
</Controls>
</Report>'
)
SELECT
m.c.value('@Value', 'varchar(max)') AS PersonId,
p.w.value('@Value', 'varchar(max)') AS Comment
FROM
@SampleTable XS
OUTER APPLY
XS.PersonXml.nodes('Report/Controls/Control[@ControlType="PersonControl"]/Fields/Field') as m(c)
OUTER APPLY
XS.PersonXml.nodes('Report/Controls/Control[@ControlType="TextControl"]/Fields/Field') as p(w)
WHERE
m.c.value('@UniqueIdentifier', 'varchar(max)') = 'PersonId'
AND m.c.value('@Value', 'varchar(max)') > 0
AND p.w.value('@UniqueIdentifier', 'varchar(max)') = 'PersonComment'
运行上述结果时,每个评论都应用于每个人,因此我不知道哪个评论适用于真实数据集中的哪个人(为了示例的目的,我在评论中包含了PersonId):
----------------------------------------------
- PersonId | Comment -
----------------------------------------------
- 12345 | Comments regarding person 12345 -
- 12345 | Comments regarding person 7890 -
- 7890 | Comments regarding person 12345 -
- 7890 | Comments regarding person 7890 -
----------------------------------------------
我正在尝试提取信息,以便获取此人及其相关评论:
----------------------------------------------
- PersonId | Comment -
----------------------------------------------
- 12345 | Comments regarding person 12345 -
- 7890 | Comments regarding person 7890 -
----------------------------------------------
我不确定这是否可行,因为我没有在SQL中操作和提取XML做太多工作。
我在MSDN上阅读了一些文章,例如:
我还看了一些关于在SQL中提取XML的其他问题,但大多数似乎与分层数据有关,或者不涉及将属性与组元素集匹配。 e.g:
我甚至不确定是否可以按照我想要的方式查询XML,但我需要从SQL查询中提取信息,否则我会编写一个C#应用程序来提取我需要的内容。 / p>
答案 0 :(得分:0)
您需要来自XML层次结构的多个级别的值。您可以使用嵌套的&#34; CROSS APPLY nodes()&#34;操作:
SELECT ParentId = c.n.value('@ParentId', 'uniqueidentifier'),
Label = f.n.value('@Label', 'varchar(50)'),
Value = f.n.value('@Value', 'varchar(1000)')
FROM @SampleTable XS
CROSS APPLY XS.PersonXml.nodes('/Report/Controls/Control') c(n)
CROSS APPLY c.n.nodes('Fields/Field') f(n)
或者一个nodes()操作一直向下到Fields级别,并使用父节点引用返回ParentId:
SELECT ParentId = f.n.value('../../@ParentId', 'uniqueidentifier'),
Label = f.n.value('@Label', 'varchar(50)'),
Value = f.n.value('@Value', 'varchar(1000)')
FROM @SampleTable XS
CROSS APPLY XS.PersonXml.nodes('/Report/Controls/Control/Fields/Field') f(n)
然后选择上面的一个并使用PIVOT将行放在一起:
SELECT * FROM (
[chosen query from above]
) b
PIVOT (MAX(Value) FOR Label IN ([PersonId], [Comment])) x