Sql 依赖insert语句

Sql 依赖insert语句,sql,insert,bulkinsert,dml,identity-insert,Sql,Insert,Bulkinsert,Dml,Identity Insert,我有一个表,其中有一个客户的数据,客户(姓名、地址),行如“John Doe”、“Some Street 123”。对于表中的每一行,我想在Person(id,name)表中插入一行,在Address(id,Person_id,Address)表中插入一行 我可以通过为Customer中的每一行运行两条insert语句来实现这一点: insert into Person(name) values (@name); insert into Address(person_id, address) v

我有一个表,其中有一个客户的数据,客户(姓名、地址),行如“John Doe”、“Some Street 123”。对于表中的每一行,我想在Person(id,name)表中插入一行,在Address(id,Person_id,Address)表中插入一行

我可以通过为Customer中的每一行运行两条insert语句来实现这一点:

insert into Person(name) values (@name);
insert into Address(person_id, address) values (scope_identity(), @address);
但这是低效的。我想批量插入,有点像这样:

-- This works, the problem is with the Address table...
insert into Person(name)
select name from Customer

-- This looks good but does not work because name is not unique.
insert into Address(person_id, address)
select p.person_id, c.address
from Customer c join Person p on c.name = p.name

最好在两个表中都创建一些具有唯一类型的字段,因为它们是相关的。否则,由于没有条件的唯一字段,您需要联接。最好在两个表中都创建一些具有唯一类型的字段,因为它们是相关的。否则,由于没有条件的唯一字段,您需要联接正如您所解释的,因为您丢失了第一次插入的每行的scope_identity()值

解决方法是将客户主键字段添加到Person表中,然后将第二次插入与此字段联接:

在Person上插入create customerID字段之前

alter table Person add customerID int null;
然后批量插入:

-- inserting customerID
insert into Person(name, customerID)
select name, customerID from Customer

-- joining on customerID.
insert into Address(person_id, address)
select p.person_id, c.address
  from Customer c 
  join Person p on c.customerID = p.customerID
之后,您可以从Person表中删除customerID字段:

alter table Person drop column customerID

正如您所解释的,无法做到这一点,因为您丢失了第一次插入的每一行的scope_identity()值

解决方法是将客户主键字段添加到Person表中,然后将第二次插入与此字段联接:

在Person上插入create customerID字段之前

alter table Person add customerID int null;
然后批量插入:

-- inserting customerID
insert into Person(name, customerID)
select name, customerID from Customer

-- joining on customerID.
insert into Address(person_id, address)
select p.person_id, c.address
  from Customer c 
  join Person p on c.customerID = p.customerID
之后,您可以从Person表中删除customerID字段:

alter table Person drop column customerID

把这篇文章留给和我一样发现这篇文章的谷歌同行

我找到了这个解决方案,它似乎工作得很好,不需要任何时髦的模式更改:

它们使用
MERGE
语句对第一个表(生成要在其他地方使用的标识的表)执行初始插入。它使用
MERGE
语句的原因是,它允许您使用
OUTPUT
语句,您可以使用该语句从源表中输出新标识值和标识值(与在标准的
INSERT
上使用
OUTPUT
语句不同,后者不允许您输出源表标识)。您可以将此输出数据插入映射表,并使用该映射表执行第二次插入

以下是我的解决方案示例代码:

------------------------------------------------------------------------------

------------------------------------------------------------------------------
-- Set up sample schema and data
------------------------------------------------------------------------------
--Source Data
IF OBJECT_ID('dbo.tmp1') IS NOT NULL DROP TABLE dbo.tmp1 --SELECT * FROM dbo.tmp1
CREATE TABLE dbo.tmp1 (tmp1ID INT IDENTITY(1,1), Col1 CHAR(1) NOT NULL, Col2 CHAR(1) NOT NULL, Col3 CHAR(1) NOT NULL, Col4 CHAR(1) NOT NULL, Col5 CHAR(1) NOT NULL, Col6 CHAR(1) NOT NULL)

INSERT INTO dbo.tmp1 (Col1, Col2, Col3, Col4, Col5, Col6)
SELECT x.c1, x.c2, x.c3, x.c4, x.c5, x.c6
FROM (VALUES ('A','B','C','D','E','F'),
             ('G','H','I','J','K','L'),
             ('M','N','O','P','Q','R')
) x(c1,c2,c3,c4,c5,c6)

IF OBJECT_ID('dbo.tmp3') IS NOT NULL DROP TABLE dbo.tmp3 --SELECT * FROM dbo.tmp3
IF OBJECT_ID('dbo.tmp2') IS NOT NULL DROP TABLE dbo.tmp2 --SELECT * FROM dbo.tmp2

--Taget tables to split into
CREATE TABLE dbo.tmp2 (
      tmp2ID INT IDENTITY(1,1) NOT NULL CONSTRAINT PK_tmp2 PRIMARY KEY CLUSTERED (tmp2ID ASC)
    , Col1 CHAR(1) NOT NULL
    , Col2 CHAR(1) NOT NULL
    , Col3 CHAR(1) NOT NULL
)

CREATE TABLE dbo.tmp3 (
      tmp2ID INT NOT NULL
    , Col4 CHAR(1) NOT NULL
    , Col5 CHAR(1) NOT NULL
    , Col6 CHAR(1) NOT NULL
    , CONSTRAINT FK_tmp3_tmp2ID FOREIGN KEY(tmp2ID) REFERENCES dbo.tmp2 (tmp2ID)
)
------------------------------------------------------------------------------

------------------------------------------------------------------------------
-- Split data into two tables
------------------------------------------------------------------------------
DECLARE @Mapping TABLE (tmp1ID INT NOT NULL, tmp2ID INT NOT NULL);

--Use merge statment to output the source data PK as well as the newly inserted identity to generate a mapping table
MERGE INTO dbo.tmp2 AS tgt
USING dbo.tmp1 AS src ON (1=0)
WHEN NOT MATCHED THEN
    INSERT (    Col1,     Col2,     Col3)
    VALUES (src.Col1, src.Col2, src.Col3)
OUTPUT src.tmp1ID, Inserted.tmp2ID INTO @Mapping (tmp1ID, tmp2ID);

--Use the mapping table to insert the split data into the second table
INSERT INTO dbo.tmp3 (tmp2ID, Col4, Col5, Col6)
SELECT t2.tmp2ID, t1.Col4, t1.Col5, t1.Col6
FROM dbo.tmp2 t2
    JOIN @Mapping m ON m.tmp2ID = t2.tmp2ID
    JOIN dbo.tmp1 t1 ON t1.tmp1ID = m.tmp1ID

SELECT tmp2ID, Col1, Col2, Col3 FROM dbo.tmp2
SELECT tmp2ID, Col4, Col5, Col6 FROM dbo.tmp3
------------------------------------------------------------------------------

------------------------------------------------------------------------------
-- Clean up
------------------------------------------------------------------------------
DROP TABLE dbo.tmp1
DROP TABLE dbo.tmp3
DROP TABLE dbo.tmp2
------------------------------------------------------------------------------

------------------------------------------------------------------------------
GO

把这篇文章留给和我一样发现这篇文章的谷歌同行

我找到了这个解决方案,它似乎工作得很好,不需要任何时髦的模式更改:

它们使用
MERGE
语句对第一个表(生成要在其他地方使用的标识的表)执行初始插入。它使用
MERGE
语句的原因是,它允许您使用
OUTPUT
语句,您可以使用该语句从源表输出新标识值和标识值(与在标准的
INSERT
上使用
OUTPUT
语句不同,后者不允许您输出源表标识)。您可以将此输出数据插入映射表,并使用该映射表执行第二次插入

以下是我的解决方案示例代码:

------------------------------------------------------------------------------

------------------------------------------------------------------------------
-- Set up sample schema and data
------------------------------------------------------------------------------
--Source Data
IF OBJECT_ID('dbo.tmp1') IS NOT NULL DROP TABLE dbo.tmp1 --SELECT * FROM dbo.tmp1
CREATE TABLE dbo.tmp1 (tmp1ID INT IDENTITY(1,1), Col1 CHAR(1) NOT NULL, Col2 CHAR(1) NOT NULL, Col3 CHAR(1) NOT NULL, Col4 CHAR(1) NOT NULL, Col5 CHAR(1) NOT NULL, Col6 CHAR(1) NOT NULL)

INSERT INTO dbo.tmp1 (Col1, Col2, Col3, Col4, Col5, Col6)
SELECT x.c1, x.c2, x.c3, x.c4, x.c5, x.c6
FROM (VALUES ('A','B','C','D','E','F'),
             ('G','H','I','J','K','L'),
             ('M','N','O','P','Q','R')
) x(c1,c2,c3,c4,c5,c6)

IF OBJECT_ID('dbo.tmp3') IS NOT NULL DROP TABLE dbo.tmp3 --SELECT * FROM dbo.tmp3
IF OBJECT_ID('dbo.tmp2') IS NOT NULL DROP TABLE dbo.tmp2 --SELECT * FROM dbo.tmp2

--Taget tables to split into
CREATE TABLE dbo.tmp2 (
      tmp2ID INT IDENTITY(1,1) NOT NULL CONSTRAINT PK_tmp2 PRIMARY KEY CLUSTERED (tmp2ID ASC)
    , Col1 CHAR(1) NOT NULL
    , Col2 CHAR(1) NOT NULL
    , Col3 CHAR(1) NOT NULL
)

CREATE TABLE dbo.tmp3 (
      tmp2ID INT NOT NULL
    , Col4 CHAR(1) NOT NULL
    , Col5 CHAR(1) NOT NULL
    , Col6 CHAR(1) NOT NULL
    , CONSTRAINT FK_tmp3_tmp2ID FOREIGN KEY(tmp2ID) REFERENCES dbo.tmp2 (tmp2ID)
)
------------------------------------------------------------------------------

------------------------------------------------------------------------------
-- Split data into two tables
------------------------------------------------------------------------------
DECLARE @Mapping TABLE (tmp1ID INT NOT NULL, tmp2ID INT NOT NULL);

--Use merge statment to output the source data PK as well as the newly inserted identity to generate a mapping table
MERGE INTO dbo.tmp2 AS tgt
USING dbo.tmp1 AS src ON (1=0)
WHEN NOT MATCHED THEN
    INSERT (    Col1,     Col2,     Col3)
    VALUES (src.Col1, src.Col2, src.Col3)
OUTPUT src.tmp1ID, Inserted.tmp2ID INTO @Mapping (tmp1ID, tmp2ID);

--Use the mapping table to insert the split data into the second table
INSERT INTO dbo.tmp3 (tmp2ID, Col4, Col5, Col6)
SELECT t2.tmp2ID, t1.Col4, t1.Col5, t1.Col6
FROM dbo.tmp2 t2
    JOIN @Mapping m ON m.tmp2ID = t2.tmp2ID
    JOIN dbo.tmp1 t1 ON t1.tmp1ID = m.tmp1ID

SELECT tmp2ID, Col1, Col2, Col3 FROM dbo.tmp2
SELECT tmp2ID, Col4, Col5, Col6 FROM dbo.tmp3
------------------------------------------------------------------------------

------------------------------------------------------------------------------
-- Clean up
------------------------------------------------------------------------------
DROP TABLE dbo.tmp1
DROP TABLE dbo.tmp3
DROP TABLE dbo.tmp2
------------------------------------------------------------------------------

------------------------------------------------------------------------------
GO