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.