相关插入语句

发布于 2024-10-19 19:40:20 字数 684 浏览 3 评论 0原文

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

我可以通过为 Customer 中的每一行运行两个插入语句来完成此操作:

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

I have a table with data about a customer, Customer(name, address), with rows like "John Doe", "Some Street 123". For each row in the table, I want to insert one row in the Person(id, name) table and also one row in the Address(id, person_id, address) table.

I can accomplish this by running two insert statements for each row in Customer:

insert into Person(name) values (@name);
insert into Address(person_id, address) values (scope_identity(), @address);

But this is inefficient. I want to do the inserts in a batch, kind of like this:

-- 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蓝海似她心 2024-10-26 19:40:20

把这个留给像我一样找到这篇文章的谷歌旅行者。

我找到了这个解决方案,它似乎工作得很好,并且不需要任何时髦的模式更改:
https://dba.stackexchange.com/questions/160210/将数据一次性拆分为两个表

他们使用 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

Leaving this here for the fellow Google traveler that finds this post like me.

I found this solution, and it seems to work great, and doesn't require any funky schema alterations:
https://dba.stackexchange.com/questions/160210/splitting-data-into-two-tables-in-one-go

They use a MERGE statement to perform the initial insert into the first table (the table that is generating the identity to be used everywhere else). The reason it uses the MERGE statement is because it allows you to use an OUTPUT statement, which you can use to output both the new identity value as well as the identity value from the source table (as opposed to using an OUTPUT statement on a standard INSERT which does not allow you to output the source tables identity). You can insert this output data into a mapping table, and use that mapping table to perform the second insert.

Here's my sample code for the solution:

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

------------------------------------------------------------------------------
-- 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
尝蛊 2024-10-26 19:40:20

正如您所解释的那样,无法执行此操作,因为您丢失了第一次插入的每行的scope_identity() 值。

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

在插入之前,在人员上创建 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

之后,您可以从人员表中删除 customerID 字段:

alter table Person drop column customerID

there is no way to do this as you explain because you lost scope_identity() value of each row of first insert.

A work around may be add Customer primary key fields to Person table and then make join of second insert with this fields:

before insert create customerID field on Person

alter table Person add customerID int null;

then bulk inserts:

-- 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

after that you can remove customerID field from Person table:

alter table Person drop column customerID
[浮城] 2024-10-26 19:40:20

最好在两个表中创建一些与它们相关的唯一类型的字段。否则您需要连接,因为您没有条件的唯一字段

It's better that you create some field of unique types in both table are related them.otherwise you want join as you dont have unique field for condition

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文