Использование merge. .output для получения отображения между source.id и target.id

Очень упрощенно, у меня есть две таблицы 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 и узнать TargetID для каждого SourceID, потому что существуют также таблицы SourceChild и TargetChild, которые также должны быть скопированы, и мне нужно добавить новый TargetID в TargetChild. TargetID FK столбец.

Есть несколько решений для этого.

  1. Используйте цикл while или курсоры для вставки одной строки (RBAR) в Target за раз и используйте scope_identity() для заполнения FK в TargetChild.
  2. Добавьте временный столбец в @Target и вставьте SourceID. Затем вы можете присоединиться к этому столбцу, чтобы получить TargetID для FK в TargetChild.
  3. SET IDENTITY_INSERT OFF для @Target и обработайте присвоение новых значений самостоятельно. Вы получите диапазон, который затем используете в TargetChild.TargetID.

Мне не очень нравится ни один из них. Единственный, который я использовал до сих пор, - это курсоры.

Что я действительно хотел бы сделать, так это использовать output в операторе insert.

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 говорит следующее о from_table_name пункта output.

Это префикс столбца, который определяет таблицу, включенную в предложение FROM оператора DELETE, UPDATE или MERGE, которое используется для указания строк для обновления или удаления.

По какой-то причине они не говорят "строки для вставки, обновления или удаления", только "строки для обновления или удаления".

Любые мысли приветствуются, и совершенно разные решения исходной проблемы будут высоко оценены.

60
задан Mikael Eriksson 19 March 2011 в 23:25
поделиться