簡體   English   中英

將嵌套的xml解析為非規范化表

[英]Parsing nested xml into denormalized table

如何將sql server中的嵌套xml解析為單個表。 考慮到RowGuid對於每個客戶都是唯一的

例如

我想在單個表中解析此xml,該表將被非規范化並將包含一對多關系。 考慮到每個嵌套都有業務主鍵。

<Customers>
    <Customer>
         <Type xsi:nil="true" />
          <RowGuid>FEFF32BC-1DAB-4F8A-80F0-CFE293C0BEC4</RowGuid>
          <AccountId>0</AccountId>
          <AccountNumber>bdb8eb51-d</AccountNumber>
          <AccountTransactions>
            <AccountTransaction>
                <PaymentDate>2012-09-13 22:19:58</PaymentDate>
                <Balance>500</Balance>
            </AccountTransaction>
            <AccountTransaction>
                <PaymentDate>2012-09-13 22:19:58</PaymentDate>
                <Balance>500</Balance>
            </AccountTransaction>
         </AccountTransactions>
        <Addresses>
             <Address>
                    <city>DELHI</city>
             </Address>
             <Address>
                    <city>MUMBAI</city>
             </Address>
         </Addresses>
      </Customer>
    <Customer>
         <Type xsi:nil="true" />
          <RowGuid>C3D4772E-1DAB-4F8A-80F0-CFE293C0BEC4</RowGuid>
          <AccountId>0</AccountId>
          <AccountNumber>bdb8eb51-d</AccountNumber>
          <AccountTransactions>
            <AccountTransaction>
                <PaymentDate>2012-09-13 22:19:58</PaymentDate>
                <Balance>500</Balance>
            </AccountTransaction>
            <AccountTransaction>
                <PaymentDate>2012-09-13 22:19:58</PaymentDate>
                <Balance>500</Balance>
            </AccountTransaction>
         </AccountTransactions>
      </Customer>

如果不需要對table進行規范化,則可以執行LEFT JOIN 我還向Customers元素添加了名稱空間,這是因為xsi:nil="true" 試試吧:

DECLARE @xml XML =
'<Customers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Customer>
         <Type xsi:nil="true" />
          <RowGuid>FEFF32BC-1DAB-4F8A-80F0-CFE293C0BEC4</RowGuid>
          <AccountId>0</AccountId>
          <AccountNumber>bdb8eb51-d</AccountNumber>
          <AccountTransactions>
            <AccountTransaction>
                <PaymentDate>2012-09-13 22:19:58</PaymentDate>
                <Balance>500</Balance>
            </AccountTransaction>
            <AccountTransaction>
                <PaymentDate>2012-09-13 22:19:58</PaymentDate>
                <Balance>500</Balance>
            </AccountTransaction>
         </AccountTransactions>
        <Addresses>
             <Address>
                    <city>DELHI</city>
             </Address>
             <Address>
                    <city>MUMBAI</city>
             </Address>
         </Addresses>
      </Customer>
    <Customer>
         <Type xsi:nil="true" />
          <RowGuid>C3D4772E-1DAB-4F8A-80F0-CFE293C0BEC4</RowGuid>
          <AccountId>0</AccountId>
          <AccountNumber>bdb8eb51-d</AccountNumber>
          <AccountTransactions>
            <AccountTransaction>
                <PaymentDate>2012-09-13 22:19:58</PaymentDate>
                <Balance>500</Balance>
            </AccountTransaction>
            <AccountTransaction>
                <PaymentDate>2012-09-13 22:19:58</PaymentDate>
                <Balance>500</Balance>
            </AccountTransaction>
         </AccountTransactions>
      </Customer>
</Customers>'

SELECT  a.[Type],
        a.RowGuid,
        a.AccountId,
        a.AccountNumber,
        b.PaymentDate,
        b.Balance,
        c.[Address]
FROM    
(
    SELECT  
            Customer.value('Type[1]', 'VARCHAR(500)') [Type],
            Customer.value('RowGuid[1]', 'UNIQUEIDENTIFIER') RowGuid,
            Customer.value('AccountId[1]', 'INT') AccountId,
            Customer.value('AccountNumber[1]', 'VARCHAR(500)') AccountNumber
    FROM    @xml.nodes('/Customers/Customer') tbl(Customer)
) a
LEFT JOIN
(
    SELECT  
            AccountTransaction.value('PaymentDate[1]', 'DATETIME') PaymentDate,
            AccountTransaction.value('Balance[1]', 'DECIMAL(20, 2)') Balance,
            AccountTransaction.value('../../RowGuid[1]', 'UNIQUEIDENTIFIER') RowGuid
    FROM    @xml.nodes('/Customers/Customer/AccountTransactions/AccountTransaction') tbl(AccountTransaction)
)   b ON
    a.RowGuid = b.RowGuid
LEFT JOIN
(
    SELECT  
            Address.value('city[1]', 'VARCHAR(500)') [Address],
            Address.value('../../RowGuid[1]', 'UNIQUEIDENTIFIER') RowGuid
    FROM    @xml.nodes('/Customers/Customer/Addresses/Address') tbl(Address)        
)   c ON
    a.RowGuid = c.RowGuid

更新:

由於該查詢的第一個版本(使用XML數據類型方法的查詢)的查詢成本很高,因此我創建了另一個使用OPENXML而不是nodesvalue方法的版本。 在支持OPENXML方法方面,成本存在很大差異:

DECLARE @handle INT

CREATE TABLE #Customer (Type VARCHAR(500),
    RowGuid UNIQUEIDENTIFIER,
    AccountId INT,
    AccountNumber VARCHAR(500)
)

CREATE TABLE #AccountTransaction (
    PaymentDate DATETIME,
    Balance DECIMAL(20, 2),
    RowGuid UNIQUEIDENTIFIER
)

CREATE TABLE #Address (
    City VARCHAR(500),
    RowGuid UNIQUEIDENTIFIER
)

EXEC sp_xml_preparedocument @handle OUTPUT, @xml

INSERT  #Customer
SELECT  *
FROM    OPENXML(@handle, '/Customers/Customer', 2)
WITH    (
        Type VARCHAR(500),
        RowGuid UNIQUEIDENTIFIER,
        AccountId INT,
        AccountNumber VARCHAR(500)
)

INSERT  #AccountTransaction
SELECT  *
FROM    OPENXML(@handle, '/Customers/Customer/AccountTransactions/AccountTransaction', 2)
WITH    (
        PaymentDate DATETIME,
        Balance DECIMAL(20, 2),
        RowGuid UNIQUEIDENTIFIER '../../RowGuid[1]'
)

INSERT  #Address
SELECT  *
FROM    OPENXML(@handle, '/Customers/Customer/Addresses/Address', 2)
WITH    (
        city VARCHAR(500),
        RowGuid UNIQUEIDENTIFIER '../../RowGuid[1]'
)

SELECT  a.*,
        b.PaymentDate,
        b.Balance,
        c.City
FROM    #Customer a
LEFT    JOIN #AccountTransaction b ON
        b.RowGuid = a.RowGuid
LEFT    JOIN #Address c ON
        c.RowGuid = a.RowGuid

EXEC sp_xml_removedocument @handle

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM