【问题标题】:Working with nested XML nodes in SQL Server在 SQL Server 中使用嵌套的 XML 节点
【发布时间】:2017-05-04 17:13:37
【问题描述】:

XML 附在下面。我正在使用的查询返回交叉应用于每个邮政编码的地址行。

输出不正确:

Code    Reaper  PC1 PC1_AL1 PC1_AL2
Code    Reaper  PC1 PC2_AL1 PC2_AL2
Code    Reaper  PC1 PC3_AL1 PC3_AL2
... 9 rows in total

如何获得下面的预期输出?基本上我只想要旁边相应邮政编码的地址行。

Code    Reaper  PC1 PC1_AL1 PC1_AL2
Code    Reaper  PC2 PC2_AL1 PC2_AL2
Code    Reaper  PC3 PC3_AL1 PC3_AL2

这就是我正在尝试的。

DECLARE @XMLDocument XML  
SET @XMLDocument = N'<People><Person>
        <PersonDetails>
          <Surname>Code</Surname>
          <Forename>Reaper</Forename>
        </PersonDetails>
        <HomeInformation>
          <Address>
            <PostCode>PC1</PostCode>
            <AddressLines>
              <AddressLine1>PC1_AL1</AddressLine1>
              <AddressLine2>PC1_AL2</AddressLine2>
            </AddressLines>
          </Address>
          <Address>
            <PostCode>PC2</PostCode>
            <AddressLines>
              <AddressLine1>PC2_AL1</AddressLine1>
              <AddressLine2>PC2_AL2</AddressLine2>
            </AddressLines>
          </Address>
          <Address>
            <PostCode>PC3</PostCode>
            <AddressLines>
              <AddressLine1>PC3_AL1</AddressLine1>
              <AddressLine2>PC3_AL2</AddressLine2>
            </AddressLines>
          </Address>
        </HomeInformation>
      </Person>
    </People>
    '
SELECT 
    [Surname],
    [GivenName],
    [PostCode],
    [AddressLine1],
    [AddressLine2]
FROM
    (SELECT      
         ISNULL(Person.PersonDetails.value('Surname[1]', 'nvarchar(max)'),'') AS [Surname],
         ISNULL(Person.PersonDetails.value('Forename[1]', 'nvarchar(max)'),'') AS [GivenName],    
         ISNULL(HomeInformation.[Address].value('PostCode[1]', 'nvarchar(max)'),'') AS [PostCode],
         ISNULL(HomeInformationAddress.AddressLines.value('AddressLine1[1]', 'nvarchar(max)'),'') AS [AddressLine1],
         ISNULL(HomeInformationAddress.AddressLines.value('AddressLine2[1]', 'nvarchar(max)'),'') AS [AddressLine2]
     FROM  
         @XMLDocument.nodes('People/Person/PersonDetails') AS Person(PersonDetails) 
     OUTER APPLY 
         PersonDetails.nodes('../HomeInformation/Address') HomeInformation([Address])
     OUTER APPLY 
         PersonDetails.nodes('../HomeInformation/Address/AddressLines') HomeInformationAddress(AddressLines)    
    ) as X

【问题讨论】:

    标签: sql sql-server xml


    【解决方案1】:

    您应该避免向后导航。根本不需要../。尝试深入你的树层次结构:

    第一个.nodes() 调用将返回&lt;People&gt; 内的所有&lt;Person&gt; 节点。第二次调用.nodes() 返回&lt;Address&gt; 节点。最后一个返回所有&lt;AddressLine&gt; 元素。

    SELECT      
         ISNULL(prs.value('(PersonDetails/Surname/text())[1]', 'nvarchar(max)'),'') AS [Surname],
         ISNULL(prs.value('(PersonDetails/Forename/text())[1]', 'nvarchar(max)'),'') AS [GivenName],    
         ISNULL(addr.value('(PostCode/text())[1]', 'nvarchar(max)'),'') AS [PostCode],
         ISNULL(addrLn.value('(AddressLine1/text())[1]', 'nvarchar(max)'),'') AS [AddressLine1],
         ISNULL(addrLn.value('(AddressLine2/text())[1]', 'nvarchar(max)'),'') AS [AddressLine2]
     FROM  
         @XMLDocument.nodes('People/Person') AS A(prs) 
     OUTER APPLY 
         prs.nodes('HomeInformation/Address') B(addr)
     OUTER APPLY 
         addr.nodes('AddressLines') C(addrLn);
    

    您可能会read this answer 找到,为什么((.../text())[1])比简单的...[1] 更好...

    【讨论】:

    • 谢谢。我肯定会从您的回答中汲取一些最佳实践
    【解决方案2】:

    FROM 子句中的这两行相互交叉连接:

    OUTER APPLY PersonDetails.nodes('../HomeInformation/Address') HomeInformation([Address])
    OUTER APPLY PersonDetails.nodes('../HomeInformation/Address/AddressLines') HomeInformationAddress(AddressLines) 
    

    您需要使第二个依赖于第一个以防止这种情况:

    OUTER APPLY PersonDetails.nodes('../HomeInformation/Address') HomeInformation([Address])
    OUTER APPLY HomeInformation.nodes('../AddressLines') HomeInformationAddress(AddressLines) 
    

    【讨论】:

    • 你试过了吗?第二个../ 是错误的。您的解决方案没有正确返回...最初的问题是,对.nodes() 的第一次调用是深入一层...您的建议原则上是正确的,但不能修复这个初始问题。更好地向下导航严格向前...
    • 感谢您的回答。虽然我必须在最后一行 OUTER APPLY HomeInformation.Address.nodes('AddressLines') HomeInformationAddress(AddressLines) 中进行更正,但我确切地知道为什么我的代码无法正常工作。**第二个依赖于第一个**是修复。
    • @Shnugo 是的,你是对的。不幸的是,这些天我不能总是测试我的答案,因为我的 iPhone 上没有 SQL Server。
    • @RBarryYoung 通过 iPhone 回答是一个挑战:-D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-19
    相关资源
    最近更新 更多