2017-03-05 64 views
0

我在SQL Server中有以下XML,並且想要遍歷它以生成結構化消息。SQL Server XQuery - 迭代動態xml並返回自定義結構

<aggregate type="ApplicationForm"> 
    <entity type="Form" root="true" id="d799728b-7973-4046-b60f-cb25d4ee385c"> 
     <attribute name="creationDate" multivalue="false">2017-01-16</attribute> 
     <attribute name="product" multivalue="false">Abc</attribute> 
     <relation name="r_PersonMain" multivalue="false">4808f654-f480-412c-8dc5-d29c6c811602</relation>   
     <relation name="r_PersonPayer" multivalue="false">a8e9eaf2-56a5-4f88-955b-19eb98f6e882</relation> 
    </entity> 
    <entity type="Payment" root="true" id="e197bf66-1e35-42a9-bdc0-0674e3a0f765"> 
     <attribute name="totalAnnualPremium" multivalue="false">328415.81</attribute> 
     <relation name="r_PaymentMethodRecurring" multivalue="false">b8b3c652-b886-44aa-a75b-b2d3ecd6c064</relation> 
     <relation name="r_PaymentMethodFirst" multivalue="false">f3d91f99-ff6a-4888-a663-24e42ecc7342</relation> 
     <attribute name="term" multivalue="false">01</attribute>   
    </entity> 
    <entity type="Person" root="false" id="4808f654-f480-412c-8dc5-d29c6c811602"> 
     <relation name="r_AddressWork" multivalue="false">cae83657-47c2-49bd-a588-7685271c4766</relation> 
     <attribute name="idNumber" multivalue="false">1112223334447</attribute> 
     <relation name="r_SelectionItem" multivalue="true">...</relation> 
     <relation name="r_Health" multivalue="false">07d08bd6-ec73-4710-9de4-23435cd2b088</relation>  
     <relation name="r_AddressCurrent" multivalue="false">56d17bda-e332-497e-8e22-e7b7f09f996d</relation> 
     <attribute name="lastName" multivalue="false"> 1</attribute>   
     <attribute name="jobDescription1" multivalue="false"/> 
     <relation name="r_Behavior" multivalue="false">2db2c23a-37dd-4857-87b4-005aa87b2c2d</relation>  
     <attribute name="email" multivalue="false"></attribute>  
     <relation name="r_AddressRegistered" multivalue="false">ce79a468-fb26-4996-91a8-82954d960855</relation> 
     <attribute name="telephoneExtention1" multivalue="false"/> 
     <relation name="r_Occupation1" multivalue="false">b7b69acc-2945-4f64-8ffd-4537849280f5</relation>   
    </entity> 
</aggregate> 

頂部元素包含長列表entity標籤。它每個都包含兩個元素,attribute & relationattribute包含直接值,而relation包含對另一個entity標籤的引用,該標籤又包含attributerelation

爲了挑選出entity表格(第一個標籤),它需要迭代它及其所有引用,直到檢索到所有引用的entities

我可以檢索第一個實體及其關係(參考實體),然後訪問它的第二級參考實體,然後再次檢查它的內部是否存在另一個「關係」標記,那麼我也必須訪問它。

問題是,這種方法不是動態的,不能自動檢索所有引用的項目。問:我如何動態地訪問所有引用的實體及其屬性,直到沒有引用的實體了。問:我還想根據每個屬性或實體「名稱」標籤賦予我的自定義名稱分配標籤。例如creationDate,product。

這是我的查詢。

DECLARE @xml xml 
    SET @xml =(Select CAST(CAST([AAHAD].[dbo].[aq_aggregate].data AS NVARCHAR(MAX)) AS XML) 
     FROM [AAHAD].[dbo].[aq_aggregate] 
     WHERE [AAHAD].[dbo].[aq_aggregate].[aggregateId] = 2 
     FOR XML RAW, TYPE) 

SELECT @xml.query(' 
    let $xml := (/row/aggregate) 
    let $form := (/row/aggregate/entity[@type="Form"]) 

    return 
    <Form> 
     <attributes> 
     { 
      for $form_attrs in ($form/attribute) 
      return <attribute><name>{ data($form_attrs/@name) } </name><value>{ data($form_attrs) }</value></attribute> 
     } 
     </attributes> 
     <relations> 
     { 
      for $form_rel in ($form/relation) 
      let $form_rel_id := data($form_rel) 
      let $relation :=($xml/entity[@id=$form_rel_id]) 

      return 
      <relation>   
        <attributes> 
        { 
         for $innerRel_attrs in ($relation/attribute) 
         return <attribute><name>{ data($innerRel_attrs/@name) } </name><value>{ data($innerRel_attrs) }</value></attribute> 
        } 
        </attributes> 
        <relations> 
        { 
         for $innerRel_rel in ($relation/relation) 
         let $inner_Rel_id := data($innerRel_rel) 
         let $inner_Relation :=($xml/entity[@id=$inner_Rel_id]) 

         return 
         <relation>   
           <attributes> 
           { 
            for $inner2Rel_attrs in ($inner_Relation/attribute) 
            return <attribute><name>{ data($inner2Rel_attrs/@name) } </name><value>{ data($inner2Rel_attrs) }</value></attribute> 
           } 
           </attributes> 
           <relations> 
           { 
            for $inner2Rel_rel in ($inner_Relation/relation)       
            return <relation>{ ($inner2Rel_rel) }</relation> 
           } 
           </relations>    
         </relation> 
        } 
        </relations>    
      </relation> 
     } 
     </relations>   
    </Form> 
    ') 

回答

0

不知道這是你在找什麼,但我會用一個表值函數應用於動態解析幾乎所有的XML結構爲元素的層次結構,屬性和值。結果可以通過範圍鍵(R1/R2)或XPath進行處理和/或旋轉。

原始來源是http://beyondrelational.com/modules/2/blogs/28/posts/10495/xquery-lab-58-select-from-xml.aspx只做了原來的一些調整。

表現是可敬的。您的示例XML在170 ms內處理完畢。

既然你是在2008年,我應該注意到你將不得不編輯CONCAT()部分。

實施例:

Select * From [dbo].[udf-XML-Hier](@XML) Order By R1 

返回

enter image description here

的UDF如果有意

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(100)') 
        ,Attribute = cast('' as varchar(100)) 
        ,Value  = x.value('text()[1]','varchar(max)') 
        ,XPath  = cast(concat(x.value('local-name(.)','varchar(100)'),'[' ,cast(Row_Number() Over(Order By (Select 1)) as int),']') as varchar(1000)) 
        ,Seq  = cast(1000000+Row_Number() over (Order by (Select NULL)) as varchar(1000)) 
        ,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(100)') 
        ,Attribute = cast('' as varchar(100)) 
        ,Value  = cast(c.value('text()[1]','varchar(max)') as varchar(max)) 
        ,XPath  = cast(concat(p.XPath,'/',c.value('local-name(.)','varchar(100)'),'[',cast(Row_Number() Over(PARTITION BY c.value('local-name(.)','varchar(100)') Order By (Select 1)) as int),']') as varchar(1000)) 
        ,Seq  = cast(concat(p.Seq,' ',10000000+Cast((Lvl + 1) * 1024 + (Row_Number() Over(Order By (Select 1)) * 2) as int) * 10) as varchar(1000)) 
        ,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(100)') 
          ,Value  = x.value('.','varchar(max)') 
          ,XPath  = p.XPath + '/@' + x.value('local-name(.)','varchar(100)') 
          ,Seq  = cast(concat(p.Seq,' ',10000000+p.ID + Row_Number() over (Order By (Select NULL))) as varchar(1000)) 
         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+case when Attribute='' then '' else '@'+Attribute end 
     ,A.Value 
From cte1 A 

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

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

你告訴我們,你想

產生structued消息

這將有助於顯示預期的輸出...

下面的代碼將提取您的XML的所有數據在一個易於查詢的派生表

DECLARE @xml XML= 
N'<aggregate type="ApplicationForm"> 
    <entity type="Form" root="true" id="d799728b-7973-4046-b60f-cb25d4ee385c"> 
     <attribute name="creationDate" multivalue="false">2017-01-16</attribute> 
     <attribute name="product" multivalue="false">Abc</attribute> 
     <relation name="r_PersonMain" multivalue="false">4808f654-f480-412c-8dc5-d29c6c811602</relation>   
     <relation name="r_PersonPayer" multivalue="false">a8e9eaf2-56a5-4f88-955b-19eb98f6e882</relation> 
    </entity> 
    <entity type="Payment" root="true" id="e197bf66-1e35-42a9-bdc0-0674e3a0f765"> 
     <attribute name="totalAnnualPremium" multivalue="false">328415.81</attribute> 
     <relation name="r_PaymentMethodRecurring" multivalue="false">b8b3c652-b886-44aa-a75b-b2d3ecd6c064</relation> 
     <relation name="r_PaymentMethodFirst" multivalue="false">f3d91f99-ff6a-4888-a663-24e42ecc7342</relation> 
     <attribute name="term" multivalue="false">01</attribute>   
    </entity> 
    <entity type="Person" root="false" id="4808f654-f480-412c-8dc5-d29c6c811602"> 
     <relation name="r_AddressWork" multivalue="false">cae83657-47c2-49bd-a588-7685271c4766</relation> 
     <attribute name="idNumber" multivalue="false">1112223334447</attribute> 
     <relation name="r_SelectionItem" multivalue="true">...</relation> 
     <relation name="r_Health" multivalue="false">07d08bd6-ec73-4710-9de4-23435cd2b088</relation>  
     <relation name="r_AddressCurrent" multivalue="false">56d17bda-e332-497e-8e22-e7b7f09f996d</relation> 
     <attribute name="lastName" multivalue="false"> 1</attribute>   
     <attribute name="jobDescription1" multivalue="false"/> 
     <relation name="r_Behavior" multivalue="false">2db2c23a-37dd-4857-87b4-005aa87b2c2d</relation>  
     <attribute name="email" multivalue="false"></attribute>  
     <relation name="r_AddressRegistered" multivalue="false">ce79a468-fb26-4996-91a8-82954d960855</relation> 
     <attribute name="telephoneExtention1" multivalue="false"/> 
     <relation name="r_Occupation1" multivalue="false">b7b69acc-2945-4f64-8ffd-4537849280f5</relation>   
    </entity> 
</aggregate>'; 

--The查詢

WITH AllValues AS 
(
    SELECT @xml.value(N'(/aggregate/@type)[1]',N'nvarchar(max)') AS Aggregate_Type 
      ,e.value(N'@type',N'nvarchar(max)') AS Entity_Type 
      ,e.value(N'@root',N'bit') AS Entity_Root 
      ,e.value(N'@id',N'uniqueidentifier') AS [Entity_Id] 
      ,nd.value(N'local-name(.)',N'nvarchar(max)') AS Node_Type 
      ,nd.value(N'@name',N'nvarchar(max)') AS Node_Name 
      ,nd.value(N'@multivalue',N'bit') AS Node_MultiValue 
      ,nd.value(N'text()[1]',N'nvarchar(max)') AS Node_Content 
    FROM @xml.nodes(N'/aggregate/entity') AS A(e) 
    CROSS APPLY e.nodes(N'*') AS B(nd) 
) 
SELECT * FROM AllValues; 

結果(命名和(如果可能)類型):

+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| Aggregate_Type | Entity_Type | Entity_Root | Entity_Id       | Node_Type | Node_Name    | Node_MultiValue | Node_Content       | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Form  | 1   | D799728B-7973-4046-B60F-CB25D4EE385C | attribute | creationDate    | 0    | 2017-01-16       | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Form  | 1   | D799728B-7973-4046-B60F-CB25D4EE385C | attribute | product     | 0    | Abc         | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Form  | 1   | D799728B-7973-4046-B60F-CB25D4EE385C | relation | r_PersonMain    | 0    | 4808f654-f480-412c-8dc5-d29c6c811602 | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Form  | 1   | D799728B-7973-4046-B60F-CB25D4EE385C | relation | r_PersonPayer   | 0    | a8e9eaf2-56a5-4f88-955b-19eb98f6e882 | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Payment  | 1   | E197BF66-1E35-42A9-BDC0-0674E3A0F765 | attribute | totalAnnualPremium  | 0    | 328415.81       | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Payment  | 1   | E197BF66-1E35-42A9-BDC0-0674E3A0F765 | relation | r_PaymentMethodRecurring | 0    | b8b3c652-b886-44aa-a75b-b2d3ecd6c064 | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Payment  | 1   | E197BF66-1E35-42A9-BDC0-0674E3A0F765 | relation | r_PaymentMethodFirst  | 0    | f3d91f99-ff6a-4888-a663-24e42ecc7342 | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Payment  | 1   | E197BF66-1E35-42A9-BDC0-0674E3A0F765 | attribute | term      | 0    | 01         | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Person  | 0   | 4808F654-F480-412C-8DC5-D29C6C811602 | relation | r_AddressWork   | 0    | cae83657-47c2-49bd-a588-7685271c4766 | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Person  | 0   | 4808F654-F480-412C-8DC5-D29C6C811602 | attribute | idNumber     | 0    | 1112223334447      | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Person  | 0   | 4808F654-F480-412C-8DC5-D29C6C811602 | relation | r_SelectionItem   | 1    | ...         | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Person  | 0   | 4808F654-F480-412C-8DC5-D29C6C811602 | relation | r_Health     | 0    | 07d08bd6-ec73-4710-9de4-23435cd2b088 | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Person  | 0   | 4808F654-F480-412C-8DC5-D29C6C811602 | relation | r_AddressCurrent   | 0    | 56d17bda-e332-497e-8e22-e7b7f09f996d | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Person  | 0   | 4808F654-F480-412C-8DC5-D29C6C811602 | attribute | lastName     | 0    | 1         | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Person  | 0   | 4808F654-F480-412C-8DC5-D29C6C811602 | attribute | jobDescription1   | 0    | NULL         | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Person  | 0   | 4808F654-F480-412C-8DC5-D29C6C811602 | relation | r_Behavior    | 0    | 2db2c23a-37dd-4857-87b4-005aa87b2c2d | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Person  | 0   | 4808F654-F480-412C-8DC5-D29C6C811602 | attribute | email     | 0    | NULL         | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Person  | 0   | 4808F654-F480-412C-8DC5-D29C6C811602 | relation | r_AddressRegistered  | 0    | ce79a468-fb26-4996-91a8-82954d960855 | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Person  | 0   | 4808F654-F480-412C-8DC5-D29C6C811602 | attribute | telephoneExtention1  | 0    | NULL         | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 
| ApplicationForm | Person  | 0   | 4808F654-F480-412C-8DC5-D29C6C811602 | relation | r_Occupation1   | 0    | b7b69acc-2945-4f64-8ffd-4537849280f5 | 
+-----------------+-------------+-------------+--------------------------------------+-----------+--------------------------+-----------------+--------------------------------------+ 

我可以看到,該Form有通過關係人person's id 4808F...類似於付款人付款人的ID。但我不知道,你打算從這裏做什麼(這些關係是1:1還是1:n?)

+0

謝謝你的回答,雖然我在尋找類似的分層格式來生成,而不是表格。所以通過'ID'引用的所有元素都應該作爲父元素的子元素來使用。 – AAhad

+0

@AAhad這就是爲什麼你應該總是發佈**期望的輸出**。我不知道(我應該怎麼辦?)你需要什麼......如果你不提供更多的細節(閱讀我的最後一行),這是不可能回答的。以下鏈接的實體將導致*遞歸CTE *。 – Shnugo

+0

我正在尋找方法將相關實體置於一個父元素之下,那就是我一直在尋找的東西。 – AAhad