Můžete (ab)použít MERGE
s OUTPUT
doložka.
MERGE
může INSERT
, UPDATE
a DELETE
řádky. V našem případě potřebujeme pouze INSERT
.1=0 je vždy nepravda, takže NOT MATCHED BY TARGET
část se vždy provede. Obecně mohou existovat další větve, viz dokumenty.WHEN MATCHED
se obvykle používá k UPDATE
;WHEN NOT MATCHED BY SOURCE
se obvykle používá k DELETE
, ale tady je nepotřebujeme.
Tato spletitá forma MERGE
je ekvivalentní jednoduchému INSERT
,ale na rozdíl od jednoduchého INSERT
jeho OUTPUT
klauzule umožňuje odkazovat na sloupce, které potřebujeme. Umožňuje získávat sloupce ze zdrojových i cílových tabulek, čímž se ukládá mapování mezi starými a novými ID.
MERGE INTO [dbo].[Test]
USING
(
SELECT [Data]
FROM @Old AS O
) AS Src
ON 1 = 0
WHEN NOT MATCHED BY TARGET THEN
INSERT ([Data])
VALUES (Src.[Data])
OUTPUT Src.ID AS OldID, inserted.ID AS NewID
INTO @New(ID, [OtherID])
;
Ohledně vaší aktualizace a spoléhání se na pořadí vygenerovaných IDENTITY
hodnoty.
V jednoduchém případě, když [dbo].[Test]
má IDENTITY
a poté INSERT
pomocí ORDER BY
bude zaručit, že vygenerovaná IDENTITY
hodnoty budou v určeném pořadí. Viz bod 4 v Záruky objednávání v SQL Server . Nezaručuje fyzické pořadí vložených řádků, ale zaručuje pořadí, ve kterém IDENTITY
jsou generovány hodnoty.
INSERT INTO [dbo].[Test] ([Data])
SELECT [Data]
FROM @Old
ORDER BY [RowID]
Ale když použijete OUTPUT
klauzule:
INSERT INTO [dbo].[Test] ([Data])
OUTPUT inserted.[ID] INTO @New
SELECT [Data]
FROM @Old
ORDER BY [RowID]
řádky v OUTPUT
stream nejsou objednány. Alespoň, přísně vzato, ORDER BY
v dotazu platí pro primární INSERT
operace, ale není tam nic, co by říkalo, jaké je pořadí OUTPUT
. Takže bych se na to nesnažil spoléhat. Buď použijte MERGE
nebo přidejte další sloupec pro explicitní uložení mapování mezi ID.