2017-05-05 53 views
0

我有XML數據列,其中包含作爲應用程序進程的一部分的問題和答案。 我試圖通過T-SQL /動態SQL實現的目標是在任何有目標標記的地方派生出一組唯一的路徑。 所以對於下面的XML例子,我希望像T-SQL循環訪問XML數據列以獲取唯一路徑集

日誌/客戶/客戶/節/問題/ groupone /問題/目標 日誌/客戶/客戶/節/問題/ grouptwo /問題/目標

想法是,然後使用它並通過XML循環來導出所需標籤的值。即

[DATA]。價值( '(/日誌/客戶/客戶端/部分/問題/ groupone /問題/目標', 'NVARCHAR(MAX)')

問題是每個應用程序有不同的問題和XML結構,即一些集可能有更多的問題,有些人可能有不同的分組。 但我要的是,如果有一個標籤那麼什麼是它的路徑。

我怎樣才能最好地實現這一點?

<log> 
    <clients> 
    <client> 
    <section name ="Apps」> 
    <questions> 
     <groupone> 
     <question> 
     <target>Age</target> 
     </question> 
     <question> 
     <target> Height</target> 
     </question> 
     <question> 
     <target> Weight</target> 
     </question> 
     </groupone> 
     <grouptwo name = "exercise"> 
     <wording>what is your name</wording> 
     <question> 
     <id>1</id> 
     <target>def<target> 
     </question> 
     </grouptwo> 
    </questions> 
    </section> 
    </client> 
    </clients> 
</log> 

回答

3

FROM OPENXML的過時方法可能是此處的一個選項。 Check this answer

this link你會發現John Cappelletti不時發佈的一個函數,它會將任何XML(信用函數的代碼下面的信用點)分解。

但我不確定,你真的想達到什麼......你爲什麼需要這條路?如果你有興趣在所有目標節點的值是這樣的(用//深的搜索不需要確切XPath

SELECT t.value(N'(text())[1]','nvarchar(max)') 
FROM @xml.nodes('//target') AS A(t); 

如果你真的需要了所有的一切您可以檢查這一點,你可能會做一些事情:

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(1000000+Row_Number() over(Order By (Select 1)) 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 

Taken from John Cappelletti: https://stackoverflow.com/a/42729851/5089204 

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 
*/ 
GO 

DECLARE @xml XML= 
'<log> 
    <clients> 
    <client> 
    <section name ="Apps"> 
    <questions> 
     <groupone> 
     <question> 
     <target>Age</target> 
     </question> 
     <question> 
     <target> Height</target> 
     </question> 
     <question> 
     <target> Weight</target> 
     </question> 
     </groupone> 
     <grouptwo name = "exercise"> 
     <wording>what is your name</wording> 
     <question> 
     <id>1</id> 
     <target>def</target> 
     </question> 
     </grouptwo> 
    </questions> 
    </section> 
    </client> 
    </clients> 
</log>'; 

SELECT * FROM dbo.[udf-XML-Hier](@xml); 
GO 
+0

謝謝,已經解決了我的問題。一個非常動態的方法 – Sharingan