Du kan (ab)använda MERGE
med OUTPUT
klausul.
MERGE
kan INSERT
, UPDATE
och DELETE
rader. I vårt fall behöver vi bara INSERT
.1=0 är alltid false, så NOT MATCHED BY TARGET
del exekveras alltid. I allmänhet kan det finnas andra grenar, se dokument.WHEN MATCHED
används vanligtvis för att UPDATE
;WHEN NOT MATCHED BY SOURCE
används vanligtvis för att DELETE
, men vi behöver dem inte här.
Denna invecklade form av MERGE
motsvarar enkel INSERT
, men till skillnad från enkla INSERT
dess OUTPUT
klausulen gör det möjligt att referera till de kolumner som vi behöver. Den gör det möjligt att hämta kolumner från både käll- och destinationstabeller och sparar därmed en mappning mellan gamla och nya 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])
;
Angående din uppdatering och att förlita sig på ordningen för genererad IDENTITY
värden.
I det enkla fallet, när [dbo].[Test]
har IDENTITY
kolumn och sedan INSERT
med ORDER BY
kommer garantera att den genererade IDENTITY
värdena skulle vara i angiven ordning. Se punkt 4 i Beställningsgarantier i SQL Server . Tänk på att det inte garanterar den fysiska ordningen för infogade rader, men det garanterar ordningen i vilken IDENTITY
värden genereras.
INSERT INTO [dbo].[Test] ([Data])
SELECT [Data]
FROM @Old
ORDER BY [RowID]
Men när du använder OUTPUT
klausul:
INSERT INTO [dbo].[Test] ([Data])
OUTPUT inserted.[ID] INTO @New
SELECT [Data]
FROM @Old
ORDER BY [RowID]
raderna i OUTPUT
strömmen är inte beställd. Åtminstone, strängt taget, ORDER BY
i frågan gäller den primära INSERT
operation, men det finns inget där som säger vad som är ordningen för OUTPUT
. Så jag skulle inte försöka lita på det. Använd antingen MERGE
eller lägg till en extra kolumn för att explicit lagra mappningen mellan ID:n.