将嵌套的xml解析为非规范化表

时间:2012-09-14 05:15:21

标签: sql sql-server-2008 xpath

如何将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>

1 个答案:

答案 0 :(得分:5)

如果表格不需要标准化,您可以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而不是nodes和{的版本{1}}方法。支持value方法的成本差异很大:

OPENXML