如何插入多条记录并获取标识值?
Posted
技术标签:
【中文标题】如何插入多条记录并获取标识值?【英文标题】:How to insert multiple records and get the identity value? 【发布时间】:2008-09-18 19:24:11 【问题描述】:我正在从另一个表 B 向表 A 中插入多条记录。有没有办法在不使用游标的情况下获取表 A 记录的标识值并更新表 b 记录?
Create Table A
(id int identity,
Fname nvarchar(50),
Lname nvarchar(50))
Create Table B
(Fname nvarchar(50),
Lname nvarchar(50),
NewId int)
Insert into A(fname, lname)
SELECT fname, lname
FROM B
我使用的是 MS SQL Server 2005。
【问题讨论】:
安迪欧文的回答是最好的。触发器很笨拙,不适用于目标表上的任意操作,尤其是当您的目标是临时的或只是中间的时。达伦的回答是错误的,如果您要插入一组行,它们在目标表中的顺序不一定与您的集合的顺序相同。 Dmitry 的方式很糟糕,因为它需要一次循环插入一行,这在性能方面很慢,尽可能使用集合。科里的做法很糟糕,他解释了原因,“只要他们不冲突。”这将变成星期六晚上 c 我意识到这是一个老问题,它指定了 SQL Server 2005,但由于它是显示 2008 年可用的 MERGE 语句的第一个结果,以后应该提到那些寻找解决方案的人。 MERGE INTO TargetTable USING (SELECT....) AS Source ON 1 = 2 WHEN NOT MATCHED THEN INSERT.... OUTPUT inserted.ID INTO TempTable (InsertedID) 简单插入不需要合并。合并对于插入/更新很有用,但对于简单的插入来说就大材小用了。 Andy 的输出答案对我有用,并帮助取消了索引锁。 如果您要插入相关项目,您可能需要MERGE
和 OUTPUT
,因此需要一个像 (FakeID, IdentityID) 这样的映射表来了解哪个 fakeid 映射到结果 IDENTITY
价值。
【参考方案1】:
使用 2005 年的输出子句:
DECLARE @output TABLE (id int)
Insert into A (fname, lname)
OUTPUT inserted.ID INTO @output
SELECT fname, lname FROM B
select * from @output
现在您的表变量具有您插入的所有行的标识值。
【讨论】:
那么你如何更新表 B 呢?我的意思是,您如何将 @output 的每条记录与 B 中的记录关联起来?如果你使用 fname,lname 作为键,那么使用 njr 的解决方案会更简单。 @munissor,我知道这是一个旧线程,但请查看 this simple-talk article 的主题。查看“添加 OUTPUT 子句”部分。 @munissor 有点晚了,但你可以做到output inserted.id, inserted.whateverColumn into @output
请注意,当表 A 有触发器时,这会惨遭失败,因为 Microsoft 拒绝修复一个错误。另一个解决方法在这里:***.com/q/13198476/2557263【参考方案2】:
仔细阅读您的问题,您只想根据表 A 中的新标识值更新表 B。
插入完成后,只需运行更新...
UPDATE B
SET NewID = A.ID
FROM B INNER JOIN A
ON (B.FName = A.Fname AND B.LName = A.LName)
这假设 FName / LName 组合可用于键匹配表之间的记录。如果不是这种情况,您可能需要添加额外的字段以确保记录正确匹配。
如果您没有备用键来匹配记录,那么它根本没有意义,因为表 B 中的记录无法相互区分。
【讨论】:
【参考方案3】:据我了解,您遇到的问题是您想要插入到具有标识列的表 A 中,并且您想要保留没有标识列的表 B 中的标识。
为此,您只需要在表 A 上打开身份插入。这将允许您在插入时定义您的 ID,只要它们不冲突,您应该没问题。然后你可以这样做:
Insert into A(identity, fname, lname) SELECT newid, fname, lname FROM B
不确定您使用的是什么数据库,但对于 sql server,打开身份插入的命令是:
set identity_insert A on
【讨论】:
他不是在尝试更新表 A,而是在尝试更新表 B。表 B 没有标识列。【参考方案4】:我建议使用 uniqueidentifier 类型而不是标识。在这种情况下,您可以在插入之前生成 ID:
update B set NewID = NEWID()
insert into A(fname,lname,id) select fname,lname,NewID from B
【讨论】:
【参考方案5】:如果您总是想要这种行为,您可以在 TableA 上放置一个 AFTER INSERT 触发器来更新表 B。
【讨论】:
【参考方案6】:您可以通过加入row number 获得。这是可能的,因为它是一个标识,它只会随着您添加项目而增加,这将按照您选择它们的顺序。
【讨论】:
错了,记录不能保证按照你认为的顺序进入数据库。【参考方案7】:-- first create a table for show how its works
CREATE TABLE [dbo].[myTable]
(
[id] [INT] IDENTITY(1, 1) NOT NULL,
[text] [VARCHAR](10) NULL
)
ON [PRIMARY]
GO
-- var table for keep new inserted id
DECLARE @tblNewInserted TABLE
(
newids INT
)
--use the output clause in insert statement
INSERT INTO [dbo].[myTable]
output inserted.id
INTO @tblNewInserted
VALUES ('aa'),('bb'),('cc')
SELECT *
FROM @tblNewInserted
【讨论】:
【参考方案8】:MBelly 是正确的 - 但是触发器将始终尝试更新表 B,即使这不是必需的(因为您也是从表 C 插入的?)。
Darren 在这里也是正确的,您不能将多个身份作为结果集返回。您的选择是使用游标并为您插入的每一行获取标识,或者使用 Darren 的方法在前后存储标识。只要您知道身份的增量,这应该可以工作,只要您确保表针对所有三个事件都已锁定。
如果是我,而且时间不紧迫,我会选择光标。
【讨论】:
以上是关于如何插入多条记录并获取标识值?的主要内容,如果未能解决你的问题,请参考以下文章
使用 NodeJS 在 mySQL 中插入多条记录以防止注入并获取每条记录的 ID
Access SQL:从插入语句或从 DAO.QueryDef 获取受影响记录的标识值
如何从此 ADODB.Recordset 中获取插入 ID?