簡體   English   中英

如何在SQL Server中將復雜的XML解析為多個插入和更新?

[英]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.

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