Déclenchement de mise à jour SQL uniquement lorsque la colonne est modifiée


101

En regardant d'autres exemples, j'ai trouvé ce qui suit mais cela ne semble pas fonctionner comme je le souhaiterais: je veux qu'il ne mette à jour les informations modifiées que si la QtyToRepairvaleur a été mise à jour ... mais cela ne fonctionne pas cette.

Si je commente le lieu, les informations modifiées sont mises à jour dans tous les cas. Comme je l'ai dit, d'autres exemples m'ont conduit à être optimiste. Tous les indices appréciés. Merci.

Walter

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified]
   ON [dbo].[SCHEDULE]
   AFTER UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    UPDATE SCHEDULE SET modified = GETDATE()
        , ModifiedUser = SUSER_NAME()
        , ModifiedHost = HOST_NAME()
    FROM SCHEDULE S
    INNER JOIN Inserted I on S.OrderNo = I.OrderNo and S.PartNumber = I.PartNumber
    WHERE S.QtyToRepair <> I.QtyToRepair
END

8
Un avertissement à propos de update()- il ne teste que si la colonne apparaît dans la liste de mise à jour et est toujours vrai pour les insertions. Il ne vérifie pas si la valeur de la colonne a changé, car vous pouvez avoir plus d'une ligne, où certaines valeurs ont changé et d'autres pas.
Nikola Markovinović

Réponses:


128

Vous avez deux voies pour votre question:

1- Utilisez la commande de mise à jour dans votre déclencheur.

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified]
   ON [dbo].[SCHEDULE]
   AFTER UPDATE
AS BEGIN
    SET NOCOUNT ON;
    IF UPDATE (QtyToRepair) 
    BEGIN
        UPDATE SCHEDULE 
        SET modified = GETDATE()
           , ModifiedUser = SUSER_NAME()
           , ModifiedHost = HOST_NAME()
        FROM SCHEDULE S INNER JOIN Inserted I 
        ON S.OrderNo = I.OrderNo and S.PartNumber = I.PartNumber
        WHERE S.QtyToRepair <> I.QtyToRepair
    END 
END

2- Utiliser la jointure entre la table insérée et la table supprimée

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified]
   ON [dbo].[SCHEDULE]
   AFTER UPDATE
AS BEGIN
    SET NOCOUNT ON;    

    UPDATE SCHEDULE 
    SET modified = GETDATE()
       , ModifiedUser = SUSER_NAME()
       , ModifiedHost = HOST_NAME()
    FROM SCHEDULE S 
    INNER JOIN Inserted I ON S.OrderNo = I.OrderNo and S.PartNumber = I.PartNumber
    INNER JOIN Deleted D ON S.OrderNo = D.OrderNo and S.PartNumber = D.PartNumber                  
    WHERE S.QtyToRepair <> I.QtyToRepair
    AND D.QtyToRepair <> I.QtyToRepair
END

Lorsque vous utilisez la commande de mise à jour pour la table SCHEDULEet définissez la QtyToRepaircolonne sur une nouvelle valeur, si la nouvelle valeur est égale à l'ancienne valeur sur une ou plusieurs lignes, la solution 1 met à jour toutes les lignes mises à jour dans la table de planification, mais la solution 2 ne met à jour que les lignes dont l'ancienne valeur n'est pas égale à nouvelle valeur.


Désolé de ne pas avoir mentionné qu'il s'agissait de SQLServer. J'avais besoin d'utiliser la table supprimée. J'ai fini par écrire dans une table séparée (pour maintenir un historique).
Walter de Jong

9
L'approche n ° 2 est meilleure si vous ne voulez pas que votre déclencheur se déclenche si la colonne est modifiée à la même valeur.
Neolisk

2
Je pense qu'il me manque peut-être quelque chose - mais l'approche n ° 1 ne fonctionnerait pas, car c'est après la mise à jour, donc la ligne actuelle aura toujours la même valeur que la ligne d'insertion. Vous devez rejoindre pour supprimer si vous utilisez après la mise à jour
Rob

5
@Rob L'instruction "IF UPDATE" appelle une procédure qui a accès à une liste de colonnes de colonnes qui ont été mises à jour dans le cadre de la requête et n'a donc pas besoin de connaître les valeurs précédentes. (Nous venons de rencontrer cela dans notre environnement et avons confirmé que "IF UPDATE" est honoré indépendamment de la clause "
AFTER

3
pourquoi joignez inserted- vous la table dans la deuxième requête? ce devrait être la même chose que la table elle-même, n'est-ce pas?
teran

22

fyi Le code avec lequel j'ai fini:

IF UPDATE (QtyToRepair)
    begin
        INSERT INTO tmpQtyToRepairChanges (OrderNo, PartNumber, ModifiedDate, ModifiedUser, ModifiedHost, QtyToRepairOld, QtyToRepairNew)
        SELECT S.OrderNo, S.PartNumber, GETDATE(), SUSER_NAME(), HOST_NAME(), D.QtyToRepair, I.QtyToRepair FROM SCHEDULE S
        INNER JOIN Inserted I ON S.OrderNo = I.OrderNo and S.PartNumber = I.PartNumber
        INNER JOIN Deleted D ON S.OrderNo = D.OrderNo and S.PartNumber = D.PartNumber 
        WHERE I.QtyToRepair <> D.QtyToRepair
end

1
J'ai trouvé cela utile car la réponse 2- Utiliser la jointure entre ci-dessus n'a jamais fonctionné en raison du critère where WHERE S.QtyToRepair <> I.QtyToRepair AND D.QtyToRepair <> I.QtyToRepairne se déclenchant jamais / correspondant car le premier critère n'était jamais vrai - la table insérée correspondait toujours à la valeur réelle de la table. Utiliser `WHERE I.QtyToRepair <> D.QtyToRepair` était la clé pour moi. Aussi l' IF UPDATE (field)aide de plusieurs déclencheurs de tir.
Firegarden

13

On devrait vérifier si QtyToRepairest mis à jour dans un premier temps.

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified]
   ON [dbo].[SCHEDULE]
   AFTER UPDATE
AS 
BEGIN
SET NOCOUNT ON;
    IF UPDATE (QtyToRepair) 
    BEGIN
        UPDATE SCHEDULE 
        SET modified = GETDATE()
           , ModifiedUser = SUSER_NAME()
           , ModifiedHost = HOST_NAME()
        FROM SCHEDULE S INNER JOIN Inserted I 
            ON S.OrderNo = I.OrderNo and S.PartNumber =    I.PartNumber
        WHERE S.QtyToRepair <> I.QtyToRepair
    END
END

6

Vous souhaitez effectuer les opérations suivantes:

ALTER TRIGGER [dbo].[tr_SCHEDULE_Modified]
   ON [dbo].[SCHEDULE]
   AFTER UPDATE
AS 
BEGIN
SET NOCOUNT ON;

    IF (UPDATE(QtyToRepair))
    BEGIN
        UPDATE SCHEDULE SET modified = GETDATE()
            , ModifiedUser = SUSER_NAME()
            , ModifiedHost = HOST_NAME()
        FROM SCHEDULE S
        INNER JOIN Inserted I ON S.OrderNo = I.OrderNo AND S.PartNumber = I.PartNumber
        WHERE S.QtyToRepair <> I.QtyToRepair
    END
END

Veuillez noter que ce déclencheur se déclenchera chaque fois que vous mettez à jour la colonne, que la valeur soit la même ou non.


2

Chaque fois qu'un enregistrement a été mis à jour, un enregistrement est "supprimé". Voici mon exemple:

ALTER TRIGGER [dbo].[UpdatePhyDate]
   ON  [dbo].[M_ContractDT1]
   AFTER UPDATE
AS 
BEGIN
    -- on ContarctDT1 PhyQty is updated 
    -- I want system date in Phytate automatically saved
    SET NOCOUNT ON;

    declare @dt1ky as int   

    if(update(Phyqty))
    begin
        select @dt1ky = dt1ky from deleted

        update M_ContractDT1 set PhyDate=GETDATE() where Dt1Ky=  @dt1ky     

    end

END

Ça fonctionne bien

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.