2017-02-15 109 views
1

是否有一種低成本的方式來查詢具有嵌套集合模型的表格,以便從特定級別獲取節點的集合?如何從嵌套集模型中的某個級別獲取所有節點?

即如何從我的樹級別n獲得IEnumerable? 即如何從我的樹級別n-1獲取IEnumerable?

謝謝!

+0

您正在使用哪個RDMS?示例XML也會有所幫助 –

+0

謝謝@JohnCappelletti!我正在使用MSSQL。具有Id,Left,Right字段的簡單節點結構 – gapin

回答

0

也許比你需要的多一點,但它可以減少。

以下TVF將幾乎解析任何XML結構並返回規範化的層次結構。

作爲一個TVF,你可以申請任何所需WHERE,例如WHERE Lvl=3,甚至在CROSS APPLY

示例使用

Declare @XML xml='<person><firstname preferred="Annie" nickname="BeBe">Annabelle</firstname><lastname>Smith</lastname></person>' 
Select * from [dbo].[udf-XML-Hier](@XML) Order by R1 

返回

enter image description here

TVF if有興趣

CREATE FUNCTION [dbo].[udf-XML-Hier](@XML xml) 

Returns Table 
As Return 

with cte0 as ( 
        Select Lvl  = 1 
         ,ID  = Cast(1 as int) 
         ,Pt  = Cast(NULL as int) 
         ,Element = x.value('local-name(.)','varchar(150)') 
         ,Attribute = cast('' as varchar(150)) 
         ,Value  = x.value('text()[1]','varchar(max)') 
         ,XPath  = cast(concat(x.value('local-name(.)','varchar(max)'),'[' ,cast(Row_Number() Over(Order By (Select 1)) as int),']') as varchar(max)) 
         ,Seq  = cast(10000001 as varchar(max)) 
         ,AttData = x.query('.') 
         ,XMLData = x.query('*') 
        From @XML.nodes('/*') a(x) 
        Union All 
        Select Lvl  = p.Lvl + 1 
         ,ID  = Cast((Lvl + 1) * 1024 + (Row_Number() Over(Order By (Select 1)) * 2) as int) * 10 
         ,Pt  = p.ID 
         ,Element = c.value('local-name(.)','varchar(150)') 
         ,Attribute = cast('' as varchar(150)) 
         ,Value  = cast(c.value('text()[1]','varchar(max)') as varchar(max)) 
         ,XPath  = cast(concat(p.XPath,'/',c.value('local-name(.)','varchar(max)'),'[',cast(Row_Number() Over(PARTITION BY c.value('local-name(.)','varchar(max)') Order By (Select 1)) as int),']') as varchar(max)) 
         ,Seq  = cast(concat(p.Seq,' ',10000000+Cast((Lvl + 1) * 1024 + (Row_Number() Over(Order By (Select 1)) * 2) as int) * 10) as varchar(max)) 
         ,AttData = c.query('.') 
         ,XMLData = c.query('*') 
        From cte0 p 
        Cross Apply p.XMLData.nodes('*') b(c) 
      ) 
    , cte1 as ( 
        Select R1 = Row_Number() over (Order By Seq),A.* 
        From (
          Select Lvl,ID,Pt,Element,Attribute,Value,XPath,Seq From cte0 
          Union All 
          Select Lvl  = p.Lvl+1 
           ,ID  = p.ID + Row_Number() over (Order By (Select NULL)) 
           ,Pt  = p.ID 
           ,Element = p.Element 
           ,Attribute = x.value('local-name(.)','varchar(150)') 
           ,Value  = x.value('.','varchar(max)') 
           ,XPath  = p.XPath + '/@' + x.value('local-name(.)','varchar(max)') 
           ,Seq  = cast(concat(p.Seq,' ',10000000+p.ID + Row_Number() over (Order By (Select NULL))) as varchar(max)) 
          From cte0 p 
          Cross Apply AttData.nodes('/*/@*') a(x) 
         ) A 
       ) 

Select A.R1 
     ,R2 = IsNull((Select max(R1) From cte1 Where Seq Like A.Seq+'%'),A.R1) 
     ,A.Lvl 
     ,A.ID 
     ,A.Pt 
     ,A.Element 
     ,A.Attribute 
     ,A.XPath 
     ,Title = Replicate('|---',Lvl-1)+Element+IIF(Attribute='','','@'+Attribute) 
     ,A.Value 
From cte1 A 

/* 
Source: http://beyondrelational.com/modules/2/blogs/28/posts/10495/xquery-lab-58-select-from-xml.aspx 
*/