Attivazione dell'aggiornamento SQL solo quando la colonna viene modificata


101

Guardando altri esempi ho trovato quanto segue ma non sembra funzionare come vorrei: voglio che aggiorni le informazioni modificate solo se il QtyToRepairvalore è stato aggiornato ... ma non funziona quello.

Se commento il dove, le informazioni modificate vengono aggiornate in ogni caso. Come ho detto altri esempi mi hanno portato ad essere ottimista. Eventuali indizi apprezzati. Grazie.

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 avviso su update(): verifica solo se la colonna viene visualizzata nell'elenco degli aggiornamenti ed è sempre vero per gli inserimenti. Non controlla se il valore della colonna è cambiato, perché potresti avere più di una riga, dove alcuni valori sono cambiati e altri no.
Nikola Markovinović

Risposte:


128

Hai due modi per la tua domanda:

1- Usa il comando di aggiornamento nel tuo trigger.

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- Usa Join tra la tabella inserita e la tabella eliminata

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

Quando si utilizza il comando di aggiornamento per la tabella SCHEDULEe Imposta la QtyToRepaircolonna sul nuovo valore, se il nuovo valore è uguale al vecchio valore in una o più righe, la soluzione 1 aggiorna tutte le righe aggiornate nella tabella di pianificazione ma la soluzione 2 aggiorna solo le righe di pianificazione che il vecchio valore non è uguale a nuovo valore.


Ci scusiamo per non aver detto che era SQLServer. Avevo bisogno di usare la tabella eliminata. Ho finito per scrivere su una tabella separata (per mantenere una cronologia).
Walter de Jong

9
L'approccio n. 2 è migliore se non vuoi che il tuo trigger si attivi se la colonna viene cambiata allo stesso valore.
Neolisk

2
Penso che mi manchi qualcosa, ma l'approccio n. 1 non funzionerebbe, perché questo è dopo l'aggiornamento, quindi la riga corrente avrebbe sempre lo stesso valore della riga di inserimento. È necessario unire alla cancellato se si sta utilizzando dopo l'aggiornamento
Rob

5
@Rob L'istruzione "IF UPDATE" richiama una procedura che ha accesso a un elenco di colonne di colonne che sono state aggiornate come parte della query e quindi non ha bisogno di conoscere i valori precedenti. (Ci siamo appena imbattuti in questo nel nostro ambiente e abbiamo confermato che "IF UPDATE" è rispettato indipendentemente dalla clausola "AFTER UPDATE")
TChadwick

3
perché ti unisci al insertedtavolo nella seconda query? dovrebbe essere lo stesso del tavolo stesso, non è vero?
teran

22

fyi Il codice che ho finito con:

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
L'ho trovato utile perché la risposta 2- Usa join tra sopra non ha mai funzionato a causa del fatto che i criteri WHERE S.QtyToRepair <> I.QtyToRepair AND D.QtyToRepair <> I.QtyToRepairnon si sono mai attivati ​​/ corrispondenti poiché il primo criterio non era mai vero: la tabella inserita corrispondeva sempre al valore effettivo della tabella. Usare "WHERE I.QtyToRepair <> D.QtyToRepair" è stata la chiave per me. Anche l' IF UPDATE (field)aiuto da più trigger che sparano.
Firegarden

13

Si dovrebbe controllare se QtyToRepairè aggiornato all'inizio.

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

Vuoi fare quanto segue:

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

Tieni presente che questo trigger si attiverà ogni volta che aggiorni la colonna, indipendentemente dal fatto che il valore sia lo stesso o meno.


2

Ogni volta che un record è stato aggiornato, un record viene "eliminato". Ecco il mio esempio:

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

Funziona bene

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.