【问题标题】:SQL Server XQuery - iterate dynamic xml and return custom structureSQL Server XQuery - 迭代动态 xml 并返回自定义结构
【发布时间】:2017-07-25 05:53:45
【问题描述】:

我在 SQL Server 中有以下 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 标签。每个都包含两个元素,attributerelationattribute 包含直接值,而 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>
  ') 

【问题讨论】:

    标签: sql-server xml sql-server-2008-r2 sqlxml xquery-sql


    【解决方案1】:

    不确定这是否是您要查找的内容,但我将使用 Table-Valued-Function 将几乎任何 XML 结构动态解析为元素、属性和值的层次结构。可以通过范围键 (R1/R2) 或 XPath 处理和/或旋转结果。

    原始来源是http://beyondrelational.com/modules/2/blogs/28/posts/10495/xquery-lab-58-select-from-xml.aspx 仅对原始来源做了一些调整。

    表现可圈可点。您的示例 XML 已在 170 毫秒内处理完毕。

    由于您是 2008 年,我应该注意您必须编辑 CONCAT() 部分。

    示例:

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

    退货

    有兴趣的 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
    */
    

    【讨论】:

      【解决方案2】:

      你告诉我们你想要

      生成结构化消息

      这将有助于显示预期的输出...

      以下代码将在一个易于查询的派生表中提取您的 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>';
      

      --查询

      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 通过人的 id 4808F... 与人有关系,类似于 payer vai payer's id。但我不知道,你要从这里做什么(这些关系是 1:1 还是 1:n?)

      【讨论】:

      • 感谢您的回答,尽管我一直在寻找要生成的类似分层格式而不是表格。这样所有通过“ID”引用的元素都应该作为父元素的子元素。
      • @AAhad 这就是为什么您应该始终发布预期输出的原因。我不知道(我应该怎么做?)您需要什么...如果您不提供更多详细信息(请阅读我的最后几行),则无法回答。跟随链接实体链将导致递归 CTE
      • 我一直在寻找将相关实体置于一个父元素下的方法,这正是我所寻找的。​​span>
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 2020-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-28
      相关资源
      最近更新 更多