2013-04-09 20 views
1

我找到了解析xml插入的例子。然而這些例子非常簡單。 他們通常只是這樣的:如何將複雜的XML解析爲SQL服務器中的多個插入和更新?

<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迭代和第一行插入表「家」 後,我返回ID爲家庭和在表中使用它作爲下一個INSERT外鍵一個人「人」與愛好相同。我想你應該已經明白了。在「家庭」之後,我需要做一些更新陳述,然後再轉到下一個家庭。

難道有人指着我正確的方向嗎?將不勝感激。

+0

哪些服務器端語言是您使用..? – alwaysLearn 2013-04-09 07:35:50

+0

坦率地說,你已經完成了作業所期望的功課並不清楚。 Google很容易找到這個頁面,顯示從xml文件中選擇兩個相關的表格:http://www.mssqltips.com/sqlservertip/2899/importing-and-processing-data-from-xml-files-into-sql-server -tables /。看來你必須做多次傳球。 – koriander 2013-04-09 08:04:54

+0

如果您使用的是SQL Server 2008或更高版本,則可以使用[本答案]中的技術(http://stackoverflow.com/a/12853080/569436) – 2013-04-09 08:08:42

回答

2

不幸的是,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 
0

這裏的主要問題是,你可以有相同的名字,許多家庭。我的解決方案考慮到這個「方面」(注意:我使用了修改的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