我正在使用 sp_xml_preparedocument 进行批量插入。但我想在父表中进行批量插入,为每个新插入的行获取 scope_identity,然后在子表中批量插入。
我可以通过在过程中为父表获取表变量并在该表中插入我应该插入到父表中的数据来做到这一点。现在遍历游标中的每一行,插入实际表,然后插入子表。
但是有没有没有光标的击球方式?我想要一些最佳解决方案
我正在使用 sp_xml_preparedocument 进行批量插入。但我想在父表中进行批量插入,为每个新插入的行获取 scope_identity,然后在子表中批量插入。
我可以通过在过程中为父表获取表变量并在该表中插入我应该插入到父表中的数据来做到这一点。现在遍历游标中的每一行,插入实际表,然后插入子表。
但是有没有没有光标的击球方式?我想要一些最佳解决方案
如果您使用的是 SQL Server 2008 或更高版本,则可以按照此问题中的说明使用合并。
创建一个表变量,当对Parent
. 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);
总是,因为游标是邪恶的!
我假设您有某种方法可以将子记录从源文件链接到父记录。我还假设您从 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
从那里,你应该没事。