MERGE avec OUTPUT ne semble pas faire la bonne chose

8

J'ajoute une clé étrangère à une table et je supprime toutes les lignes qui violent le FK, en les copiant dans une table ModifiedTable_invalid. Dans le cadre du script, j'ai la commande MERGE suivante:

MERGE ModifiedTable t1
USING TargetTable tt
ON t1.JoinColumn = tt.JoinColumn
WHEN MATCHED THEN
    UPDATE SET t1.FkColumn = tt.FkSource
WHEN NOT MATCHED BY SOURCE THEN DELETE
OUTPUT DELETED.* INTO ModifiedTable_invalid;

Cependant, cette commande semble insérer CHAQUE ligne de ModifiedTable dans ModifiedTable_invalid, pas seulement celles supprimées par la commande MERGE. Que se passe-t-il et comment puis-je obtenir qu'il ne mette que les lignes supprimées dans ModifiedTable_invalid?

thecoop
la source

Réponses:

11

Lorsque vous mettez à jour une ligne, elle apparaîtra dans les pseudo-tables ( insertedvaleur post-mise à jour) et deleted(valeur pré-mise à jour). Si cela semble étrange, considérez qu'une mise à jour est logiquement une suppression suivie d'une insertion (bien que la mise à jour ne puisse pas être effectuée physiquement de cette façon).

Lorsqu'elle est utilisée avec MERGE, la OUTPUTclause peut inclure une colonne supplémentaire nommée $action. L' ajout de cette colonne à votre requête montrera quelle action a été prise ( 'INSERT', 'UPDATE'ou 'DELETE') pour chaque ligne.

Par exemple:

insert into ModifiedTable_invalid(Id /* And other columns */)
select
    Id
    /* And other columns */
from
(
    merge ModifiedTable t1
    using TargetTable t2 on t1.JoinColumn = t2.JoinColumn
    when matched then update set t1.FkColumn = t2.FkSource
    when not matched by source then delete
    output 
        $action as DMLAction,
        deleted.Id as Id /* And other columns... */
) outputs
where
    DMLAction = 'DELETE';

Les lignes mises à jour auront $action= 'UPDATE'.

Voir également le post d'Adam Machanic sur l'utilisation de OUTPUT avec l'instruction MERGE pour d'autres exemples intéressants.

Kevin Feasel
la source
Ce comportement n'a aucun sens pour moi. Pourquoi les lignes qui n'ont pas été supprimées apparaissent-elles DELETED.*?
thecoop
3
@thecoop - Il vous permet d'accéder aux valeurs "avant" et "après" pour une mise à jour. Sur le plan conceptuel, vous pouvez considérer une mise à jour comme une suppression suivie d'une insertion même si ce n'est souvent pas comme cela que cela se passe réellement.
Martin Smith