XML 到 SQL 个结果集。多级嵌套
XML to SQL result set. Multiple nesting levels
本质上,我正在尝试使用 SQL.
将我拥有的 XML 转换为平面数据结构
我的 XML 采用以下格式(我已将 XML 更改为一个子集,以简化我的示例):
<Actions>
<AddComponent>
<Action>
<DataItem>
<GroupId>1</GroupId>
<Data>
<Id>100</Id>
<Value>Value A</Value>
<Children>
<Data>
<Id>200</Id>
<Value>Value B</Value>
<Children>
<Data>
<Id>300</Id>
<Value>Value C1</Value>
</Data>
<Data>
<Id>301</Id>
<Value>Value C2</Value>
<Children />
</Data>
</Children>
</Data>
</Children>
</Data>
</DataItem>
<DataItem>
<GroupId>2</GroupId>
<Data>
<Id>101</Id>
<Value>Value A</Value>
<Children>
<Data>
<Id>200</Id>
<Value>Value B</Value>
<Children>
<Data>
<Id>302</Id>
<Value>Value C3</Value>
</Data>
</Children>
</Data>
</Children>
</Data>
</DataItem>
</Action>
</AddComponent>
</Actions>
我正在寻找的输出如下:
+---------+-----+----------+----------+
| GroupId | Id | Value | ParentId |
+---------+-----+----------+----------+
| 1 | 100 | Value A | NULL |
| 1 | 200 | Value B | 100 |
| 1 | 300 | Value C1 | 200 |
| 1 | 301 | Value C2 | 200 |
| 2 | 101 | Value A | NULL |
| 2 | 200 | Value B | 101 |
| 2 | 302 | Value C3 | 200 |
+---------+-----+----------+----------+
我不确定递归遍历 'Children' 元素的最佳方法。由于 children 的数量可以无限增加。
检查此查询是否有帮助:
DECLARE @XML XML = '<Actions><AddComponent><Action><DataItem><GroupId>1</GroupId><Data><Id>100</Id><Value>Value A</Value><Children><Data><Id>200</Id><Value>Value B</Value><Children><Data><Id>300</Id><Value>Value C1</Value></Data><Data><Id>301</Id><Value>Value C2</Value><Children /></Data></Children></Data></Children></Data></DataItem><DataItem><GroupId>2</GroupId><Data><Id>101</Id><Value>Value A</Value><Children><Data><Id>200</Id><Value>Value B</Value><Children><Data><Id>302</Id><Value>Value C3</Value></Data></Children></Data></Children></Data></DataItem></Action></AddComponent></Actions>';
;WITH cte
AS (SELECT c.value('(GroupId)[1]', 'varchar(30)') groupid,
c.value('(Data/Id)[1]', 'varchar(30)') id,
c.value('(Data/Value)[1]', 'varchar(30)') value,
c.query('Data/Children') AS childdata,
Cast(NULL AS VARCHAR(30)) AS parentId
FROM (SELECT @xml) temp(x)
CROSS apply x.nodes('//Actions/AddComponent/Action/DataItem') tabl(c)
UNION ALL
SELECT groupid,
c.value('(Id)[1]', 'varchar(30)') id,
c.value('(Value)[1]', 'varchar(30)') value,
c.query('Children') AS childdata,
Cast(cte.id AS VARCHAR(30)) AS parentId
FROM cte
CROSS apply childdata.nodes('/Children/Data') tabl(c))
SELECT groupid,
id,
value,
parentId
FROM cte
ORDER BY groupid,id
正如您在我的 CTE 中所见,我首先提取所有父节点数据及其子节点 XML,然后递归地从子节点 XML.
获取所有子节点数据
select DI.X.value('(GroupId/text())[1]', 'int') as GroupId,
D.X.value('(Id/text())[1]', 'int') as Id,
D.X.value('(Value/text())[1]', 'nvarchar(50)') as Value,
D.X.value('(../../Id/text())[1]', 'int') as ParentID
from @XML.nodes('/Actions/AddComponent/Action/DataItem') as DI(X)
cross apply DI.X.nodes('.//Data') as D(X)
.//Data
将递归地为您提供所有 Data
节点。
注意:使用父轴 (../../Id/text())[1]
获取 ParentID
可能会降低性能。用你的数据试试看它的性能是否可以接受。
更新:
在 nodes()
调用中执行父轴看起来会给您更好的查询计划。
select DI.X.value('(GroupId/text())[1]', 'int') as GroupId,
D.X.value('(Id/text())[1]', 'int') as Id,
D.X.value('(Value/text())[1]', 'nvarchar(50)') as Value,
P.X.value('text()[1]', 'int') as ParentID
from @XML.nodes('/Actions/AddComponent/Action/DataItem') as DI(X)
cross apply DI.X.nodes('.//Data') as D(X)
outer apply D.X.nodes('../../Id') as P(X)
本质上,我正在尝试使用 SQL.
将我拥有的 XML 转换为平面数据结构我的 XML 采用以下格式(我已将 XML 更改为一个子集,以简化我的示例):
<Actions>
<AddComponent>
<Action>
<DataItem>
<GroupId>1</GroupId>
<Data>
<Id>100</Id>
<Value>Value A</Value>
<Children>
<Data>
<Id>200</Id>
<Value>Value B</Value>
<Children>
<Data>
<Id>300</Id>
<Value>Value C1</Value>
</Data>
<Data>
<Id>301</Id>
<Value>Value C2</Value>
<Children />
</Data>
</Children>
</Data>
</Children>
</Data>
</DataItem>
<DataItem>
<GroupId>2</GroupId>
<Data>
<Id>101</Id>
<Value>Value A</Value>
<Children>
<Data>
<Id>200</Id>
<Value>Value B</Value>
<Children>
<Data>
<Id>302</Id>
<Value>Value C3</Value>
</Data>
</Children>
</Data>
</Children>
</Data>
</DataItem>
</Action>
</AddComponent>
</Actions>
我正在寻找的输出如下:
+---------+-----+----------+----------+
| GroupId | Id | Value | ParentId |
+---------+-----+----------+----------+
| 1 | 100 | Value A | NULL |
| 1 | 200 | Value B | 100 |
| 1 | 300 | Value C1 | 200 |
| 1 | 301 | Value C2 | 200 |
| 2 | 101 | Value A | NULL |
| 2 | 200 | Value B | 101 |
| 2 | 302 | Value C3 | 200 |
+---------+-----+----------+----------+
我不确定递归遍历 'Children' 元素的最佳方法。由于 children 的数量可以无限增加。
检查此查询是否有帮助:
DECLARE @XML XML = '<Actions><AddComponent><Action><DataItem><GroupId>1</GroupId><Data><Id>100</Id><Value>Value A</Value><Children><Data><Id>200</Id><Value>Value B</Value><Children><Data><Id>300</Id><Value>Value C1</Value></Data><Data><Id>301</Id><Value>Value C2</Value><Children /></Data></Children></Data></Children></Data></DataItem><DataItem><GroupId>2</GroupId><Data><Id>101</Id><Value>Value A</Value><Children><Data><Id>200</Id><Value>Value B</Value><Children><Data><Id>302</Id><Value>Value C3</Value></Data></Children></Data></Children></Data></DataItem></Action></AddComponent></Actions>';
;WITH cte
AS (SELECT c.value('(GroupId)[1]', 'varchar(30)') groupid,
c.value('(Data/Id)[1]', 'varchar(30)') id,
c.value('(Data/Value)[1]', 'varchar(30)') value,
c.query('Data/Children') AS childdata,
Cast(NULL AS VARCHAR(30)) AS parentId
FROM (SELECT @xml) temp(x)
CROSS apply x.nodes('//Actions/AddComponent/Action/DataItem') tabl(c)
UNION ALL
SELECT groupid,
c.value('(Id)[1]', 'varchar(30)') id,
c.value('(Value)[1]', 'varchar(30)') value,
c.query('Children') AS childdata,
Cast(cte.id AS VARCHAR(30)) AS parentId
FROM cte
CROSS apply childdata.nodes('/Children/Data') tabl(c))
SELECT groupid,
id,
value,
parentId
FROM cte
ORDER BY groupid,id
正如您在我的 CTE 中所见,我首先提取所有父节点数据及其子节点 XML,然后递归地从子节点 XML.
获取所有子节点数据select DI.X.value('(GroupId/text())[1]', 'int') as GroupId,
D.X.value('(Id/text())[1]', 'int') as Id,
D.X.value('(Value/text())[1]', 'nvarchar(50)') as Value,
D.X.value('(../../Id/text())[1]', 'int') as ParentID
from @XML.nodes('/Actions/AddComponent/Action/DataItem') as DI(X)
cross apply DI.X.nodes('.//Data') as D(X)
.//Data
将递归地为您提供所有 Data
节点。
注意:使用父轴 (../../Id/text())[1]
获取 ParentID
可能会降低性能。用你的数据试试看它的性能是否可以接受。
更新:
在 nodes()
调用中执行父轴看起来会给您更好的查询计划。
select DI.X.value('(GroupId/text())[1]', 'int') as GroupId,
D.X.value('(Id/text())[1]', 'int') as Id,
D.X.value('(Value/text())[1]', 'nvarchar(50)') as Value,
P.X.value('text()[1]', 'int') as ParentID
from @XML.nodes('/Actions/AddComponent/Action/DataItem') as DI(X)
cross apply DI.X.nodes('.//Data') as D(X)
outer apply D.X.nodes('../../Id') as P(X)