2017-05-04 51 views
3

XML附在下面。我正在使用的查詢返回交叉應用於每個郵政編碼的地址行。在SQL Server中使用嵌套的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 

回答

0

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) 
+1

你試試這個?第二個「../」是錯誤的。你的解決方案不能正確地返回......最初的問題是,第一次調用'.nodes()'會深入到一個層次......原則上你的建議是正確的,但不能修復這個初始問題。更好地向下導航... – Shnugo

+0

感謝您的答案。雖然我不得不在最後一行'OUTER APPLY HomeInformation.Address.nodes('AddressLines')HomeInformationAddress(AddressLines)'中進行修正,但是我確切知道爲什麼我的代碼無法工作。**第二個依賴於第一個一個**是修復。 – CodeReaper

+0

@Shnugo是的,你是對的。不幸的是,現在我無法總是測試我的答案,因爲我的iPhone上沒有SQL Server。 – RBarryYoung

1

您應該避免後退導航。根本不需要../。嘗試向更深入的樹層次移動:

第一個.nodes()呼叫將返回<People>內的所有<Person>節點。第二次調用.nodes()返回<Address>節點。最後一個返回所有<AddressLine>元素。

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] ...

+0

謝謝。絕對有一些最佳實踐,我會從你的答案中拿出 – CodeReaper