使用sp_xml_preparedocument在父表和子表中批量插入

时间:2013-05-23 13:36:34

标签: sql sql-server bulkinsert

我正在使用sp_xml_preparedocument进行批量插入。但是我想在父表中进行批量插入,为每个新插入的行获取scope_identity,然后在子表中进行批量插入。

我可以通过在过程中为父表获取表变量并在该表中插入我应该在父表中插入的数据来完成此操作。现在循环遍历游标中的每一行,插入实际表中,然后插入子表。

但是没有光标没有任何击球方式吗? 我想要一些最佳解决方案

2 个答案:

答案 0 :(得分:7)

如果您使用的是SQL Server 2008或更高版本,则可以使用this question中所述的合并。

创建一个表变量,该变量将在对Parent进行合并时从父表中捕获生成的id以及子XML。然后从表变量中插入Child

注意:我使用XML数据类型而不是openxml。

表:

create table Parent
(
  ParentID int identity primary key,
  Name varchar(10) not null
);

create table Child
(
  ChildID int identity primary key,
  Name varchar(10) not null,
  ParentID int not null references Parent(ParentID)
);

XML:

<root>
  <parent>
    <name>parent 1</name>
    <child>
      <name>child 1</name>
    </child>
    <child>
      <name>child 2</name>
    </child>
  </parent>
  <parent>
    <name>parent 2</name>
    <child>
      <name>child 3</name>
    </child>
  </parent>
</root>

代码:

declare @Child table
(
  ParentID int primary key,
  Child xml
);

merge Parent as P
using (
      select T.X.value('(name/text())[1]', 'varchar(10)') as Name,
             T.X.query('child') as Child
      from @XML.nodes('/root/parent') as T(X)
      ) as X
on 0 = 1
when not matched then
  insert (Name) values (X.Name)
output inserted.ParentID, X.Child into @Child;

insert into Child(Name, ParentID)
select T.X.value('(name/text())[1]', 'varchar(max)'),
       C.ParentID
from @Child as C
  cross apply C.Child.nodes('/child') as T(X);

SQL Fiddle

答案 1 :(得分:0)

总是,因为游标是邪恶的!

我假设你有办法将子记录链接到源文件中的父记录。我还假设您是从XML文件批量插入的,其中子表在XML中表示为子节点?如果你能给我们一个你想要处理的XML的例子,那将是一个很好的帮助。现在,我们假设您的XML看起来有点像:

<root>
    <parent>
        <num>1</num>
        <name>P1</name>
        <children>
            <child>
                <num>1</num>
                <name>C1</name>
            </child>
            ...

您的父表将包含parent_key

DECLARE @parent TABLE (
    num INT,
    parent_name VARCHAR(100),
    parent_key INT
)

和子表将拥有它自己的字段,以及来自父级的标识元素:

DECLARE @child TABLE (
    num INT,
    child_name VARCHAR(100),
    parent_num INT
)

填充父表,这很容易,所以我不打算包含一个例子。将parent_key字段保留为NULL,以便只填充您知道的值。

子表填充了

INSERT INTO @child
SELECT * FROM OpenXML(@iDoc, '/root/parent/children/child', 2) WITH (
    num INT,
    name VARCHAR(100),
    parent_num INT AS '../../num'
)

正常插入父表:

INSERT INTO #parent (num, parent_name)
SELECT num, parent_name FROM @parent ORDER BY num

然后,使用ROW_NUMBER和@@ IDENTITY,您可以派生用于父主键的标识值。

;WITH cte1 AS (SELECT COUNT(*) AS cnt FROM @parent),
cte2 AS (SELECT ROW_NUMBER() OVER (ORDER BY num) AS row_num, num FROM #parent)
UPDATE p SET parent_key = @@IDENTITY - cte1.cnt + cte2.row_num
FROM @parent p, cte1, cte2
WHERE p.num = cte2.num

从那里,你应该没事。