Very simplified, I have two tables Source and 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')
I would like to move all rows from @Source
to @Target
and know the TargetID
for each SourceID
because there are also the tables SourceChild
and TargetChild
that needs to be copied as well and I need to add the new TargetID
into TargetChild.TargetID
FK column.
There are a couple of solutions to this.
- Use a while loop or cursors to insert one row (RBAR) to Target at a time and use
scope_identity()
to fill the FK ofTargetChild
. - Add a temp column to
@Target
and insertSourceID
. You can then join that column to fetch theTargetID
for the FK inTargetChild
. SET IDENTITY_INSERT OFF
for@Target
and handle assigning new values yourself. You get a range that you then use inTargetChild.TargetID
.
I'm not all that fond of any of them. The one I used so far is cursors.
What I would really like to do is to use the output
clause of the insert statement.
insert into @Target(TargetName)
output inserted.TargetID, S.SourceID
select SourceName
from @Source as S
But it is not possible
The multi-part identifier "S.SourceID" could not be bound.
But it is possible with a merge.
merge @Target as T
using @Source as S
on 0=1
when not matched then
insert (TargetName) values (SourceName)
output inserted.TargetID, S.SourceID;
Result
TargetID SourceID
----------- -----------
2 1
4 3
I want to know if you have used this? If you have any thoughts about the solution or see any problems with it? It works fine in simple scenarios but perhaps something ugly could happen when the query plan get really complicated due to a complicated source query. Worst scenario would be that the TargetID/SourceID pairs actually isn't a match.
MSDN has this to say about the from_table_name
of the output clause.
Is a column prefix that specifies a table included in the FROM clause of a DELETE, UPDATE, or MERGE statement that is used to specify the rows to update or delete.
For some reason they don't say "rows to insert, update or delete" only "rows to update or delete".
Any thoughts are welcome and totally different solutions to the original problem is much appreciated.