如何将嵌套的XML转换成对应的表?
How to convert nested XML into corresponding tables?
我有一个复杂的嵌套 XML(从 C# 实体图生成),例如:
<Customers>
<Customer>
<Id>1</Id>
<Number>12345</Number>
<Addresses>
<Address>
<Id>100</Id>
<Street>my street </street>
<city>London</city>
</Address>
<Address>
<Id>101</Id>
<street>my street 2</street>
<city>Berlin</city>
</Address>
</Addresses>
<BankDetails>
<BankDetail>
<Id>222</Id>
<Iban>DE8439834934939434333</Iban>
</BankDetail>
<BankDetail>
<Id>228</Id>
<Iban>UK1237921391239123213</Iban>
</BankDetail>
</BankDetails>
<Orders>
<Order>
<OrderLine>
</OrderLine>
</Order>
</Orders>
</Customer>
</Customers>
在将上面的XML数据存入实际的table之前,我需要先处理一下。为此,我创建了相应的 table 类型。这些 table 类型中的每一个都有一个额外的列(guid 作为 ROWGUID),因此如果我正在处理新数据(尚未分配主键),我会生成一个唯一键。我使用此专栏来保持不同 table 类型之间的关系完整性。
将上面嵌套的 XML 转换为相应的 table 的 SQL 语法是什么,记住子记录必须引用生成的父 guid?
这样试试:
DECLARE @xml XML=
N'<Customers>
<Customer>
<Id>1</Id>
<AccountNumber>12345</AccountNumber>
<Addresses>
<Address>
<Id>100</Id>
<street>my street></street>
<city>London</city>
</Address>
<Address>
<Id>101</Id>
<street>my street></street>
<city>Berlin</city>
</Address>
</Addresses>
<BankDetails>
<BankDetail>
<Id>222</Id>
<Iban>DE8439834934939434333</Iban>
</BankDetail>
<BankDetail>
<Id>228</Id>
<Iban>UK1237921391239123213</Iban>
</BankDetail>
</BankDetails>
<Orders>
<Order>
<OrderLine />
</Order>
</Orders>
</Customer>
</Customers>';
--这个查询将创建一个table#tmpInsert,其中包含所有数据
SELECT cust.value('Id[1]','int') AS CustomerID
,cust.value('AccountNumber[1]','int') AS CustomerAccountNumber
,addr.value('Id[1]','int') AS AddressId
,addr.value('street[1]','nvarchar(max)') AS AddressStreet
,addr.value('city[1]','nvarchar(max)') AS AddressCity
,bank.value('Id[1]','int') AS BankId
,bank.value('Iban[1]','nvarchar(max)') AS BankIban
,ord.value('OrderLine[1]','nvarchar(max)') AS OrderLine
INTO #tmpInsert
FROM @xml.nodes('/Customers/Customer') AS A(cust)
OUTER APPLY cust.nodes('Addresses/Address') AS B(addr)
OUTER APPLY cust.nodes('BankDetails/BankDetail') AS C(bank)
OUTER APPLY cust.nodes('Orders/Order') AS D(ord);
--这里可以查看内容
SELECT * FROM #tmpInsert;
--清理
GO
DROP TABLE #tmpInsert
在 table 中获得所有数据后,您可以使用简单的 DISTINCT
、GROUP BY
,如果需要 ROW_NUMBER() OVER(PARTITION BY ...)
到 select每个单独设置正确的插入。
我有一个复杂的嵌套 XML(从 C# 实体图生成),例如:
<Customers>
<Customer>
<Id>1</Id>
<Number>12345</Number>
<Addresses>
<Address>
<Id>100</Id>
<Street>my street </street>
<city>London</city>
</Address>
<Address>
<Id>101</Id>
<street>my street 2</street>
<city>Berlin</city>
</Address>
</Addresses>
<BankDetails>
<BankDetail>
<Id>222</Id>
<Iban>DE8439834934939434333</Iban>
</BankDetail>
<BankDetail>
<Id>228</Id>
<Iban>UK1237921391239123213</Iban>
</BankDetail>
</BankDetails>
<Orders>
<Order>
<OrderLine>
</OrderLine>
</Order>
</Orders>
</Customer>
</Customers>
在将上面的XML数据存入实际的table之前,我需要先处理一下。为此,我创建了相应的 table 类型。这些 table 类型中的每一个都有一个额外的列(guid 作为 ROWGUID),因此如果我正在处理新数据(尚未分配主键),我会生成一个唯一键。我使用此专栏来保持不同 table 类型之间的关系完整性。
将上面嵌套的 XML 转换为相应的 table 的 SQL 语法是什么,记住子记录必须引用生成的父 guid?
这样试试:
DECLARE @xml XML=
N'<Customers>
<Customer>
<Id>1</Id>
<AccountNumber>12345</AccountNumber>
<Addresses>
<Address>
<Id>100</Id>
<street>my street></street>
<city>London</city>
</Address>
<Address>
<Id>101</Id>
<street>my street></street>
<city>Berlin</city>
</Address>
</Addresses>
<BankDetails>
<BankDetail>
<Id>222</Id>
<Iban>DE8439834934939434333</Iban>
</BankDetail>
<BankDetail>
<Id>228</Id>
<Iban>UK1237921391239123213</Iban>
</BankDetail>
</BankDetails>
<Orders>
<Order>
<OrderLine />
</Order>
</Orders>
</Customer>
</Customers>';
--这个查询将创建一个table#tmpInsert,其中包含所有数据
SELECT cust.value('Id[1]','int') AS CustomerID
,cust.value('AccountNumber[1]','int') AS CustomerAccountNumber
,addr.value('Id[1]','int') AS AddressId
,addr.value('street[1]','nvarchar(max)') AS AddressStreet
,addr.value('city[1]','nvarchar(max)') AS AddressCity
,bank.value('Id[1]','int') AS BankId
,bank.value('Iban[1]','nvarchar(max)') AS BankIban
,ord.value('OrderLine[1]','nvarchar(max)') AS OrderLine
INTO #tmpInsert
FROM @xml.nodes('/Customers/Customer') AS A(cust)
OUTER APPLY cust.nodes('Addresses/Address') AS B(addr)
OUTER APPLY cust.nodes('BankDetails/BankDetail') AS C(bank)
OUTER APPLY cust.nodes('Orders/Order') AS D(ord);
--这里可以查看内容
SELECT * FROM #tmpInsert;
--清理
GO
DROP TABLE #tmpInsert
在 table 中获得所有数据后,您可以使用简单的 DISTINCT
、GROUP BY
,如果需要 ROW_NUMBER() OVER(PARTITION BY ...)
到 select每个单独设置正确的插入。