T-SQL looping through XML data column to derive unique set of paths

前端 未结 1 742
一整个雨季
一整个雨季 2020-12-20 09:05

I have XML data column which contains question and answer as part of an application process. What I am trying to achieve through T-SQL/ Dynamic SQL is to derive a unique set

相关标签:
1条回答
  • 2020-12-20 09:38

    The outdated approach with FROM OPENXML might be an option here. Check this answer.

    At this link you'll find a function John Cappelletti posted from time to time, which will shred any XML (credits below the function's code).

    But I'm not sure, what you are really trying to achieve... Why do you need the path? If you are interested in the values of all target nodes you might do something like this (deep search with // does not need the exact XPath)

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

    If you really need all and everything you can check this:

    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 讨论(0)
提交回复
热议问题