Puoi (ab)usare MERGE
con OUTPUT
clausola.
MERGE
può INSERT
, UPDATE
e DELETE
righe. Nel nostro caso dobbiamo solo INSERT
.1=0 è sempre falso, quindi NOT MATCHED BY TARGET
parte viene sempre eseguita. In generale, potrebbero esserci altri rami, vedere docs.WHEN MATCHED
è solitamente usato per UPDATE
;WHEN NOT MATCHED BY SOURCE
di solito è usato per DELETE
, ma non ne abbiamo bisogno qui.
Questa forma contorta di MERGE
è equivalente al semplice INSERT
,ma a differenza del semplice INSERT
il suo OUTPUT
La clausola consente di fare riferimento alle colonne di cui abbiamo bisogno. Consente di recuperare colonne sia dalle tabelle di origine che da quelle di destinazione salvando così una mappatura tra il vecchio e il nuovo 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])
;
Per quanto riguarda il tuo aggiornamento e fare affidamento sull'ordine di IDENTITY
generato valori.
Nel caso semplice, quando [dbo].[Test]
ha IDENTITY
colonna, quindi INSERT
con ORDER BY
farà garantire che l'IDENTITY
generato i valori sarebbero nell'ordine specificato. Vedere il punto 4 in Ordinazione delle garanzie in SQL Server . Intendiamoci, non garantisce l'ordine fisico delle righe inserite, ma garantisce l'ordine in cui IDENTITY
vengono generati valori.
INSERT INTO [dbo].[Test] ([Data])
SELECT [Data]
FROM @Old
ORDER BY [RowID]
Ma quando usi OUTPUT
clausola:
INSERT INTO [dbo].[Test] ([Data])
OUTPUT inserted.[ID] INTO @New
SELECT [Data]
FROM @Old
ORDER BY [RowID]
le righe in OUTPUT
flusso non sono ordinati. Almeno, a rigor di termini, ORDER BY
nella query si applica al INSERT
principale operazione, ma non c'è nulla che dica qual è l'ordine dell'OUTPUT
. Quindi, non proverei a fare affidamento su quello. Usa MERGE
oppure aggiungi una colonna aggiuntiva per memorizzare la mappatura tra gli ID in modo esplicito.