我正在尝试将xml解析为表数据。但是,我只得到一排。我需要做什么才能获得所有数据?我有一个link来证明这一点。
INSERT BATCHES (BatchID, RawXML)
VALUES (1, '
<ParamData>
<moduleRole>
<moduleId>1</moduleId>
<bmRoleId>4</bmRoleId>
<moduleId>2</moduleId>
<bmRoleId>8</bmRoleId>
<moduleId>3</moduleId>
<bmRoleId>255</bmRoleId>
<moduleId>8</moduleId>
<bmRoleId>4</bmRoleId>
<moduleId>16</moduleId>
<bmRoleId>4</bmRoleId>
<moduleId>64</moduleId>
<bmRoleId>4</bmRoleId>
<moduleId>128</moduleId>
<bmRoleId>4</bmRoleId>
</moduleRole>
</ParamData>
');
SELECT
b.BatchID,
x.XmlCol.value('(moduleId)[1]','INT') AS moduleId,
x.XmlCol.value('(bmRoleId)[1]','INT') AS bmRoleId
FROM
Batches b
CROSS APPLY
b.RawXml.nodes('/ParamData/moduleRole') x(XmlCol);
答案 0 :(得分:3)
我认为要在moduleId
上粉碎XML,然后选择当前元素和最近的兄弟bmRoleId
元素:
SELECT b.BatchID,
x.XmlCol.value('.','INT') AS moduleId,
x.XmlCol.value('following-sibling::bmRoleId)[1]','INT') AS bmRoleId
FROM Batches b
CROSS APPLY b.RawXml.nodes('/ParamData/moduleRole/moduleId') x(XmlCol);
不幸的是,SQL Server不支持following-sibling
轴,所以我们需要使用this post中提到的技巧:
SELECT b.BatchID,
x.XmlCol.value('.','INT') AS moduleId,
x.XmlCol.value('let $c := . return (../bmRoleId[. >> $c])[1]','INT') AS bmRoleId
FROM Batches b
CROSS APPLY b.RawXml.nodes('/ParamData/moduleRole/moduleId') x(XmlCol);
<强> sqlfiddle demo
强>
此部分return (../bmRoleId[. >> $c])[1]
,获取位于当前bmRoleId
之后的所有moduleId
(由$c
引用),然后将结果限制为第一个bmRoleId
按文档顺序
答案 1 :(得分:0)
我宁愿用数字表来解决这个问题。在我的示例中,我将从master..spt_values
创建一个 on-the-fly ,其中包含大约2.500个条目。这应该足够了。我们不需要值,只需返回ROW_NUMBER()
:
WITH Numbers AS(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Nr FROM master..spt_values)
SELECT b.BatchID
,b.RawXml.value(N'(/ParamData/moduleRole/moduleId)[sql:column("Nr")][1]','int') AS moduleId
,b.RawXml.value(N'(/ParamData/moduleRole/bmRoleId)[sql:column("Nr")][1]','int') AS bmRoleId
FROM Numbers
CROSS JOIN [BATCHES] AS b
WHERE b.RawXml.exist(N'(/ParamData/moduleRole/moduleId)[sql:column("Nr")]')=1;
结果
1 1 4
1 2 8
1 3 255
1 8 4
1 16 4
1 64 4
1 128 4
如果性能很重要,那么在TOP
之前使用ROW_NUMBER
将CROSS JOIN
的数量限制为适当的数量会有所帮助......