1

我找到了将 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”中的一个人,并且与爱好相同. 我想你应该已经明白了。在“家庭”之后,我需要在进入下一个家庭之前做一些更新声明。

有人能指出我正确的方向吗?将不胜感激。

4

2 回答 2

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
于 2013-04-09T08:02:09.463 回答
0

这里的主要问题是您可以有许多同名的家庭。我的解决方案考虑了这个“方面”(注意:我使用修改后的 XML 进行测试)。在此示例中,您可以看到两个具有相同名称 (Smith) 但不同的系列。人。这些家庭有差异。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
于 2013-04-09T09:18:19.533 回答