【问题标题】:Insert with ID from previous insert [duplicate]使用先前插入的 ID 插入 [重复]
【发布时间】:2018-09-15 10:26:49
【问题描述】:

我有具有多对多关系的表 A 和表 B。表 AB 是一个链接表。

Table:  Columns:
A       { Id, Name }
AB      { A_Id, B_Id }
B       { Id, Name }

我想将行插入到表 A 中,然后使用该行的 Id(Id 具有自动递增标识)插入到链接表中。

是否可以在单个 SQL 命令中完成?

示例(伪sql):

insert into A (Name) values (@name)
insert into AB (A_Id, B_Id) values ([previous id], @b_Id)

【问题讨论】:

标签: sql sql-server sql-insert


【解决方案1】:

是的:

INSERT INTO A (Name) VALUES (@name)

INSERT INTO AB (A_Id, B_Id)
SELECT A.Id, @B_Id
FROM A
WHERE A.Name = @name
ORDER BY A.Id

更新:此解决方案基于在您插入表 AB 时了解表 A 的约束条件。如果表 A 中有预先存在的 @name 值(即重复),那么您可能需要考虑添加额外的约束。不知道数据模型就很难知道。不过,我怀疑您正在使用维度表,这意味着不会有重复的值,因为预计您已经有了它的映射。

这也带来了一个好点;确保映射表上有一个主键,其中包含表 A 和 B 的外键列。此外,在表 A 中的 Name 列上创建唯一索引。不应允许重复,因为这会破坏映射表.

【讨论】:

  • 错误:这会将 所有 A 记录链接到 B_Id
  • @PeterB 我已经更新了我的答案。
  • 正如您所说,不能保证 Name 是唯一的(例如表 A = Customer 和 @name = 'John Smith')。 Name 也可能没有索引,使其变慢。所有这些都可以通过使用自 SQL 2008 以来存在的output 来避免。
  • @PeterB 由于使用了映射表,这不太可能。如果要插入的 Name 值已经存在,则多对多映射将被破坏 - 源映射表上必须有唯一记录。在这种情况下, A.Name 应该有一个唯一的索引。因此,您的解决方案和我的解决方案都将起作用。这归结为个人喜好。
【解决方案2】:

您可以使用返回最后插入的身份的@@IDENTITY,请参阅https://docs.microsoft.com/en-us/sql/t-sql/functions/identity-transact-sql

【讨论】:

  • 我不喜欢这个答案,因为这很危险。什么返回身份?那张桌子上真正的最后一个插入?如果同时插入两行或多行会发生什么。触发器在后台将另一行插入到另一个表中会发生什么?
  • 我同意@BerndOtt,但如果有人真正使用单条记录插入,scope_identity() 函数实际上会相对安全(至少更安全),只要有' t 背景触发做疯狂的事情。
  • 是的,它更好,但是当您插入多行时,scope_identity 仍然不起作用。
【解决方案3】:

在 SQL Server 中,最安全的方法是使用output 子句,解释为here

declare @ids table (id int);

insert into A (Name)
    output inserted.id into @ids
    values (@name);

insert into AB (A_Id, B_Id) 
    select i.id, @b_Id
    from @ids i;

为什么output 更安全?首先,它不依赖事务或会话语义。它只是捕获实际插入的数据,并使其可用于后续语句。

其次,它可以处理插入的多行(尽管在这种情况下这不是问题)。

第三,它可以返回除id之外的其他列,可以很方便。

【讨论】:

  • @ids 需要别名吗? from @ids i;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-25
  • 1970-01-01
  • 1970-01-01
  • 2016-12-22
  • 1970-01-01
  • 2023-04-02
  • 2014-01-29
相关资源
最近更新 更多