我应该从sql server 2012中的XML列中提取数据。此列的某些值将包含多个节点。不幸的是,XML没有根节点,因此使用CROSS APPLY似乎不起作用。
简化示例:
<header><msg_type>TYPE_ONE</msg_type>
<status><status_1>aaaa</status_1><status_2>bbbb</status_2>
<node_1><customerID>1234</customerID><zipcode>11111</zipcode>...</node_1>
<node_2><customerID>1234</customerID><ordernum>12345</ordernum><data2>A</ordernum>...</node_2>
<node_2><customerID>1234</customerID><ordernum>34567></ordernum><data2>B</ordernum>...</node_2>
<node_3><customerID>1234</customerID><delivery>2014-05-05 14:00:00></delivery>...</node_3>
<node_1><customerID>ABCD</customerID><zipcode>12345</zipcode>...</node_1>
<node_2><customerID>ABCD</customerId><ordernum>123536</ordernum><data2>C</ordernum>...</node_2>
<node_3><customerID>ABCD</customerID><delivery>2014-05-05 16:00:00>...</node_3>
。 。
(... =更多元素)
以下是针对其中一种多节点类型使用CROSS APPLY的示例:
select
t.InfoXML.value( '/node_1/customerID)[1]', 'varchar(50)' ) as CustomerId
, CA.Det.value( '(/node_2/ordernum)[1]', 'varchar(20)') as OrderNumber
, CA.Det.value( '(/node_2/data2)[1]', 'varchar(5)' ) as Data2
from TableUnderTest as t
CROSS APPLY t.InfoXML.nodes( '/node_2') as CA(Det)
where t.InfoXML.value( '(/header/msg_type)[1]', 'varchar(20)') = 'TYPE_ONE'
这有结果
CustomerID OrderNumber Data2
================================
1234 12345 A
1234 12345 A
1234 12345 A
我目前的想法是创建一个临时表,并在将XML值包装在根节点中之后插入XML字段(与WHERE子句匹配),然后尝试从临时表中获取数据。我目前努力设置第一部分:
Declare @Rooted Table (Rec XML);
insert into @Rooted(Rec)
(
select (convert (XML, '<root>', + convert(varchar(MAX),
t.XmlData.query('./') + '<\root>')) as Rec
from TableUnderTest t
where t.XmlData.value( '(/header/msg_type)[1]', 'varchar(20)' ) = 'TYPE_ONE'
)
现在,上面给出了语法错误。
我想要输出的内容如下:
CustomerID ZipCode OrderNumber Data2 Delivery status2
-------------------------------------------------------------------
1234 11111 12345 A 2014-05-05 14:00:00 aaaa
1234 11111 34567 B 2014-05-05 14:00:00 aaaa
ABCD 12345 123456 D 2014-05-05 15:00:00 aaaa
最好的方法是什么? (这是用于测试,而不是生产,因此性能并不重要。)我上个月只学习编写XML的SQL查询,所以也许我忽略了一些东西。看来关键问题是缺少XML的根节点,但我该如何解决它呢?