Du kan (ab)bruge MERGE
med OUTPUT
klausul.
MERGE
kan INSERT
, UPDATE
og DELETE
rækker. I vores tilfælde behøver vi kun at INSERT
.1=0 er altid falsk, så NOT MATCHED BY TARGET
del udføres altid. Generelt kan der være andre grene, se docs.WHEN MATCHED
bruges normalt til at UPDATE
;WHEN NOT MATCHED BY SOURCE
bruges normalt til at DELETE
, men vi har ikke brug for dem her.
Denne indviklede form for MERGE
svarer til simpel INSERT
, men i modsætning til simpel INSERT
dens OUTPUT
klausulen gør det muligt at henvise til de kolonner, vi har brug for. Det giver mulighed for at hente kolonner fra både kilde- og destinationstabeller og dermed gemme en kortlægning mellem gamle og nye ID'er.
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])
;
Med hensyn til din opdatering og afhængig af rækkefølgen af genereret IDENTITY
værdier.
I det simple tilfælde, når [dbo].[Test]
har IDENTITY
kolonne, derefter INSERT
med ORDER BY
vil garantere, at den genererede IDENTITY
værdier ville være i den angivne rækkefølge. Se punkt 4 i Bestillingsgarantier i SQL Server . Husk, det garanterer ikke den fysiske rækkefølge af indsatte rækker, men det garanterer rækkefølgen, hvori IDENTITY
værdier genereres.
INSERT INTO [dbo].[Test] ([Data])
SELECT [Data]
FROM @Old
ORDER BY [RowID]
Men når du bruger OUTPUT
klausul:
INSERT INTO [dbo].[Test] ([Data])
OUTPUT inserted.[ID] INTO @New
SELECT [Data]
FROM @Old
ORDER BY [RowID]
rækkerne i OUTPUT
stream er ikke bestilt. I det mindste strengt taget ORDER BY
i forespørgslen gælder for den primære INSERT
operation, men der er intet der, der siger, hvad rækkefølgen er af OUTPUT
. Så det ville jeg ikke prøve at stole på. Brug enten MERGE
eller tilføj en ekstra kolonne for at gemme tilknytningen mellem ID'er eksplicit.