【发布时间】:2011-07-18 22:45:16
【问题描述】:
很简单,我有两张表Source和Target。
declare @Source table (SourceID int identity(1,2), SourceName varchar(50))
declare @Target table (TargetID int identity(2,2), TargetName varchar(50))
insert into @Source values ('Row 1'), ('Row 2')
我想将所有行从 @Source 移动到 @Target 并知道每个 SourceID 的 TargetID 因为还有表 SourceChild 和 TargetChild 也需要复制,并且我需要将新的TargetID 添加到TargetChild.TargetID FK 列中。
有几个解决方案。
- 使用 while 循环或游标一次将一行 (RBAR) 插入到 Target,并使用
scope_identity()填充TargetChild的 FK。 - 将临时列添加到
@Target并插入SourceID。然后,您可以加入该列以获取TargetID中的 FK 的TargetChild。 -
SET IDENTITY_INSERT OFF用于@Target并自己处理分配新值。您会得到一个范围,然后在TargetChild.TargetID中使用。
我不是很喜欢他们中的任何一个。我目前使用的是游标。
我真正想做的是使用插入语句的output 子句。
insert into @Target(TargetName)
output inserted.TargetID, S.SourceID
select SourceName
from @Source as S
但这是不可能的
The multi-part identifier "S.SourceID" could not be bound.
但是可以通过合并来实现。
merge @Target as T
using @Source as S
on 0=1
when not matched then
insert (TargetName) values (SourceName)
output inserted.TargetID, S.SourceID;
结果
TargetID SourceID
----------- -----------
2 1
4 3
我想知道你有没有用过这个?如果您对解决方案有任何想法或发现任何问题?它在简单的场景中运行良好,但当查询计划由于复杂的源查询而变得非常复杂时,可能会发生一些丑陋的事情。最坏的情况是 TargetID/SourceID 对实际上不匹配。
MSDN 对output 子句的from_table_name 有这样的说法。
是一个列前缀,它指定包含在 DELETE、UPDATE 或 MERGE 语句的 FROM 子句中的表,用于指定要更新或删除的行。
出于某种原因,他们不会说“要插入、更新或删除的行”,而只会说“要更新或删除的行”。
欢迎提出任何想法,非常感谢对原始问题完全不同的解决方案。
【问题讨论】:
-
他们没有提到'insert'的原因是因为from_table_name在insert into/output语句中是无效的,“deleted”前缀也是如此(因为没有现有数据可以通过插入来更改)跨度>
-
Adam Machanic 关于合并功能的博文太棒了!解决了我的确切问题。感谢马丁史密斯发帖。希望我能给的不仅仅是 +1
-
Adam Machanic 文章的替代链接dataeducation.com/…
标签: sql-server sql-server-2008 merge