2015-01-07 40 views
2

本質上,我試圖將使用SQL的XML轉換爲平面數據結構。XML到SQL結果集。多個嵌套層次

我的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'元素的最佳方法。由於兒童人數可能無限。

+0

檢查此:http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes –

回答

4
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) 
1

檢查該查詢,如果它能夠幫助:

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所有子數據。