使用 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 INTO
和OUTPUT
来实现:
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 子句)
根据 with 子句中的条件选择要使用的 select 语句