[英]How to parse complex XML to multiple inserts and updates in SQL server?
我發現了將xml解析為插入的示例。 但是這些例子確實很簡單。 它們通常是這樣的:
<person>
<name>Martin</name>
</person>
<person>
<name>John</name>
</person>
但是我有與此類似的XML-在這里我需要在其他表中插入子元素。
<root>
<family>
<name>Smith</name>
<address>Some road 1</address>
<persons>
<person>
<name>Tina</name>
<hobbies>
<hobby>Some hobby 1</hobby>
<hobby>Some hobby 2</hobby>
</hobbies>
</person>
<person>
<name>Martin</name>
<hobbies>
<hobby>Some hobby 1</hobby>
<hobby>Some hobby 2</hobby>
</hobbies>
</person>
</persons>
</family>
<family>
<name>Lane</name>
<address>Some road 1</address>
<persons>
<person>
<name>Kevin</name>
<hobbies>
<hobby>Some hobby 1</hobby>
<hobby>Some hobby 2</hobby>
</hobbies>
</person>
<person>
<name>Julia</name>
<hobbies>
<hobby>Some hobby 1</hobby>
<hobby>Some hobby 2</hobby>
</hobbies>
</person>
</persons>
</family>
</root>
我需要遍歷此xml,首先將一行插入表“ Families”中,然后返回該家庭的ID,並在下一個INSERT中將其用作表“ Persons”中某個人的外鍵,並與嗜好相同。 我想你應該已經明白了。 在“家庭”之后,我需要做一些更新聲明,然后再繼續下一個家庭。
有人可以指出我正確的方向嗎? 將不勝感激。
不幸的是,SQL Server不支持多表插入,因此您需要執行以下單個插入:
insert into family
select f.node.value('name[1]', 'varchar(32)') as name
from @xml.nodes('/root/family') f(node)
insert into person
select family.ID as familyID, p.node.value('name[1]', 'varchar(32)') as name
from @xml.nodes('/root/family') f(node)
cross apply f.node.nodes('persons/person') p(node)
inner join family on f.node.value('name[1]', 'varchar(32)') = family.name
這里的主要問題是您可以有許多同名家庭。 我的解決方案考慮到了這一“方面”(注意:我使用了經過修改的XML進行測試)。 在此示例中,您可以看到兩個具有相同名稱(史密斯)但不同的科。 人。 這些家庭有差異。 RowNum(和FamilyID)。 棘手的部分是在最后一個CROSS APPLY
,它為每個姓氏出現都提取了所有/person
元素:
CROSS APPLY @x.nodes('/root/family[name=sql:column("f.Name")][sql:column("f.RowNum")]/persons/person') AS a(b)
注意:您也可以開發此解決方案以提取每個愛好。
DECLARE @x XML = N'
<root>
<family>
<name>Smith</name>
<address>Some road 1</address>
<persons>
<person>
<name>Tina</name>
<hobbies>
<hobby>Some hobby 1</hobby>
<hobby>Some hobby 2</hobby>
</hobbies>
</person>
<person>
<name>Martin</name>
<hobbies>
<hobby>Some hobby 1</hobby>
<hobby>Some hobby 2</hobby>
</hobbies>
</person>
</persons>
</family>
<family>
<name>Lane</name>
<address>Some road 1</address>
<persons>
<person>
<name>Kevin</name>
<hobbies>
<hobby>Some hobby 1</hobby>
<hobby>Some hobby 2</hobby>
</hobbies>
</person>
<person>
<name>Julia</name>
<hobbies>
<hobby>Some hobby 1</hobby>
<hobby>Some hobby 2</hobby>
</hobbies>
</person>
</persons>
</family>
<family>
<name>Smith</name>
<address>Some another road 11</address>
<persons>
<person>
<name>Coco</name>
</person>
<person>
<name>Jambo</name>
</person>
</persons>
</family>
</root>';
DECLARE @Family TABLE (
FamilyID INT IDENTITY(1,1) UNIQUE,
Name NVARCHAR(50) NOT NULL,
RowNum INT NOT NULL,
PRIMARY KEY (Name, RowNum)
);
INSERT @Family (Name, RowNum)
SELECT src.Name,
ROW_NUMBER() OVER(PARTITION BY src.Name ORDER BY @@SPID) AS RowNum
FROM (
SELECT a.b.value('(name)[1]', 'NVARCHAR(50)') AS Name
FROM @x.nodes('/root/family') AS a(b)
) src;
SELECT f.*
FROM @Family AS f
DECLARE @Person TABLE (
PersonID INT IDENTITY(1,1) UNIQUE,
FamilyID INT NOT NULL, -- Kind of FK
Name NVARCHAR(50) NOT NULL,
RowNum INT NOT NULL,
PRIMARY KEY (Name, RowNum)
)
INSERT @Person (FamilyID, Name, RowNum)
SELECT src.FamilyID,
src.Name,
ROW_NUMBER() OVER(PARTITION BY src.FamilyID, src.Name ORDER BY @@SPID) AS RowNum
FROM (
SELECT f.FamilyID,
a.b.value('(name)[1]', 'NVARCHAR(50)') AS Name
FROM @family f
CROSS APPLY @x.nodes('/root/family[name=sql:column("f.Name")][sql:column("f.RowNum")]/persons/person') AS a(b)
) src;
SELECT p.*
FROM @Person AS p;
結果:
FamilyID Name RowNum
-------- ----- ------
1 Lane 1
2 Smith 1
3 Smith 2
PersonID FamilyID Name RowNum
-------- -------- ------ ------
5 3 Coco 1
6 3 Jambo 1
1 1 Julia 1
2 1 Kevin 1
3 2 Martin 1
4 2 Tina 1
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.