使用 OUTPUT 子句从 SELECT INSERT 语句中检索原始身份和新身份映射

Posted

技术标签:

【中文标题】使用 OUTPUT 子句从 SELECT INSERT 语句中检索原始身份和新身份映射【英文标题】:Retrieve original and new identities mapping from SELECT INSERT statement using OUTPUT clause 【发布时间】:2014-07-10 14:32:28 【问题描述】:

我有一个包含两列的表格:

CREATE TABLE MyTable(
  Id int IDENTITY(1,1) NOT NULL,
  Name nvarchar(100) NOT NULL);

我想使用 SELECT INSERT 语句复制数据:

INSERT INTO MyTable (Name)
SELECT Name FROM MyTable

这是棘手的部分 - 我想检索原始身份和新身份之间的映射表:

DECLARE @idsMap TABLE (OriginalId int, NewId int)

我知道我想使用OUTPUT clause,但由于某种原因它不起作用:

INSERT INTO MyTable (Name)
OUTPUT t.Id, INSERTED.Id INTO @idsMap (OriginalId, NewId)
SELECT Name FROM MyTable t
-- Returns error The multi-part identifier "t.Id" could not be bound.

相关问题:can SQL insert using select return multiple identities?Possible to insert with a Table Parameter, and also retrieve identity values?

【问题讨论】:

“名称”字段中的值是唯一的还是有重复项?意思是,在通过此查询复制它们之前,它们是唯一的。显然,一旦此 INSERT 运行,它们将不再是唯一的。 什么版本的 SQL Server?如果是 2008 年或以后,您可以使用 MERGE 技巧,通过查看相关问题很容易找到这里。 @srutzky,为了清楚起见,这里的问题被简化了。我不能确定数据是唯一的,即使它是唯一的,我也不想运行另一个查询,因为索引不是......我怎么能温和地说......不是最佳的。 @Damien_The_Unbeliever,我不熟悉你所说的MERGE。是不是有点像UPSERT?如何将其应用于此问题? @HuBeZa - 请参阅此related question 上最不被接受的答案。是的,它是UPSERT。你安排它实际上总是INSERT,但你可以在OUTPUT 子句中访问源表,这与INSERT 语句不同。 【参考方案1】:

可以使用MERGE INTOOUTPUT来实现:

MERGE INTO MyTable AS tgt
USING MyTable AS src ON 1=0 --Never match
WHEN NOT MATCHED THEN
INSERT (Name)
VALUES (src.Name)
OUTPUT
    src.Id,
    inserted.Id
INTO @idsMap;

【讨论】:

遇到了类似的问题并使用了这种解决方法。但它很慢:(【参考方案2】:

向 MyTable 添加一个新列怎么样?只要您需要分析或其他任何内容,您就可以保留它。我不得不说,创建表格的副本对我来说似乎有点不对劲,但这取决于你。

这样的事情可能对你有用。

alter table MyTable
add OldID int null;

INSERT INTO MyTable (Name, OldID)
SELECT Name , Id
FROM MyTable t

select * from MyTable

【讨论】:

简洁明了,可惜我做不到。这不是真正的MyTable,它是一个拥有数百万条记录的生产数据库表。如果我不能使用 OUTPUT,我的另一个选择是遍历查询结果并使用 SCOPE_IDENTITY 一个一个地构建映射,但这会更麻烦。 不,不要循环超过一百万行。凌乱不是问题,它需要几个小时才能运行。了解生产数据库。添加一列应该不是问题,但我知道有时会这样。让我想一想,我们会找到比 RBAR 更好的东西。 我有点害怕进行结构性改变,即使是暂时的。我不确定这是否符合监管规定。当涉及大量资金时,人们往往会非常严格:)

以上是关于使用 OUTPUT 子句从 SELECT INSERT 语句中检索原始身份和新身份映射的主要内容,如果未能解决你的问题,请参考以下文章

修改要插入的数据的触发器不起作用(语句包含没有 INTO 子句的 OUTPUT 子句)

说一下output子句

OUTPUT INTO 子句中可以使用哪些列?

根据 with 子句中的条件选择要使用的 select 语句

SQL - 在另一个 SELECT 的 WHERE 子句中使用 SELECT

如何在 Laravel DB::insert 中返回我的 OUTPUT 子句