Come viene eseguito un trigger T-SQL che si attiva solo su modifiche reali?


9

Ho un trigger di tabella su UPDATE e INSERT che aggiunge una riga a un'altra tabella. Deve solo aggiungere una riga se una delle quattro colonne viene modificata. Ho provato a utilizzare IF UPDATE (col) per verificare le modifiche ma ha un punto cieco. Verifica solo che è arrivato un valore. Devo andare più a fondo, ho bisogno di confrontare i valori vecchi e nuovi per vedere che si è verificato un vero cambiamento. Deve funzionare con INSERT e UPDATE.

Nel caso di un AGGIORNAMENTO è facile perché sia ​​le tabelle inserite che quelle eliminate hanno valori che posso confrontare all'interno del trigger. Tuttavia, per INSERT solo la tabella di inserimento ha valori. Poiché ho bisogno di tutto questo nello stesso trigger, come posso gestire quel caso INSERT?

Ecco lo script del trigger che voglio modificare:

ALTER TRIGGER [dbo].[trATPerson_alter] 
   ON  [mydb].[dbo].[AT_Person]
   AFTER INSERT,UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    -- Not all updates require a push
    IF (UPDATE([First_Name]) OR UPDATE([Last_Name]) OR UPDATE([JobCode]) OR UPDATE([Inactive]))
    BEGIN
        INSERT INTO [mydb].[dbo].[AT_Person_To_Push] (
                [Facility],
                [VendorID],
                [Person_code],
                [First_Name],
                [Last_Name],
                [JobCode],
                [Alink],
                [Inactive]
            )
        SELECT  [Facility],
                [VendorID],
                [Person_code],
                [First_Name],
                [Last_Name],
                [JobCode],
                [Alink],
                [Inactive]
        FROM inserted 
    END
END

2
Una breve parola sull'uso di "SE AGGIORNAMENTO (<colonna>)". Restituisce vero se il DML specifica un valore per la colonna, indipendentemente dal fatto che il valore sia effettivamente cambiato o meno.
Jonathan Fite,

Risposte:


18

È possibile gestire sia INSERT che UPDATE con un operatore EXCEPT set. EXISTS valuterà su TRUE solo se è solo un INSERT o se è un AGGIORNAMENTO con valori diversi per una di queste colonne.

IF EXISTS (
           SELECT First_Name, Last_Name, JobCoe, Inactive FROM inserted
           EXCEPT
           SELECT First_Name, Last_Name, JobCoe, Inactive FROM deleted
          )
BEGIN...

Questo è molto più elegante che guardare le varie funzioni aggiornate nelle colonne. Abbiamo combinato quelli con un po 'di codice front-end per inviare solo i valori modificati (dopo molte discussioni). L'uso di EXCEPT ha molto più senso.
Peter Schott,

2
Questo non funziona nei casi in cui 2 file vengono "scambiati" in un aggiornamento. Se abbiamo due John Smith che hanno bisogno di aggiornare i loro JobCode (primo John da 1 a 2; secondo John da 2 a 1), ciò significherebbe che non si è verificato alcun aggiornamento.
Steven Hibble,

2
@StevenHibble - Quando possibile quanto è probabile che accada? Quel caso potrebbe essere facilmente risolto includendo le colonne PK nelle istruzioni Select sopra.
Chad Estes,

1
Direi che la probabilità dipende dalla fonte dei dati e dalla probabilità di una cattiva immissione dei dati. "Oops, John Smith sbagliato ..." non sembra che non accadrà mai . In ogni caso, ciò non riguarda l'altra metà di un aggiornamento multi-riga: come si fa a inserire solo le righe che cambiano? Questo EXISTScontrolla che qualsiasi riga sia cambiata. Se mantieni l'inserzione dalla domanda, registrerai quindi tutte le righe aggiornate quando solo una cambia in modo significativo.
Steven Hibble,

2

Nel caso in cui un aggiornamento possa interessare più righe, è necessario proteggersi da due cose:

  1. Vogliamo considerare gli aggiornamenti che scambiano valori tra righe simili. Se ci sono due John Smith che hanno bisogno di aggiornare i loro JobCode (primo John da 1 a 2; secondo John da 2 a 1), dobbiamo stare attenti a dire che entrambi sono stati aggiornati.
  2. Vogliamo solo accedere alle righe modificate AT_Person_To_Push. Se vengono aggiornate 5 righe, ma solo 2 vengono aggiornate in un modo che ci interessa, è necessario elaborare solo le 2 righe pertinenti.

Ecco come lo gestirò:

  1. Sinistra join inserteda deleted, perché insertedavrà righe per inserimenti e aggiornamenti mentre deletedavrà solo righe per gli aggiornamenti.
  2. Utilizzare EXISTScon EXCEPTper trovare righe in cui i insertedvalori differiscono dai deletedvalori. Non è possibile utilizzare i.First_Name != d.First_Name OR i.Last_Name != d.Last_Name...perché la tabella eliminata sarà vuota (e LEFT JOIN restituirà valori null) quando il trigger gestisce un INSERT.
  3. Inserisci solo le righe interessate in AT_Person_To_Push.
ALTER TRIGGER [dbo].[trATPerson_alter] 
   ON  [mydb].[dbo].[AT_Person]
   AFTER INSERT,UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    INSERT INTO [mydb].[dbo].[AT_Person_To_Push] (
            [Facility],
            [VendorID],
            [Person_code],
            [First_Name],
            [Last_Name],
            [JobCode],
            [Alink],
            [Inactive]
        )
    SELECT  i.[Facility],
            i.[VendorID],
            i.[Person_code],
            i.[First_Name],
            i.[Last_Name],
            i.[JobCode],
            i.[Alink],
            i.[Inactive]
    FROM inserted i
         LEFT JOIN deleted d
           ON i.Person_code = d.Person_code
    -- Check for changes that require a push
    WHERE EXISTS (SELECT i.[First_Name], i.[Last_Name], i.[JobCode], i.[Inactive]
                  EXCEPT
                  SELECT d.[First_Name], d.[Last_Name], d.[JobCode], d.[Inactive]);
END

1

Prova questo,

Declare @Acton int=0

If exists (Select 1 from inserted)
set @Acton=1

If exists (Select 1 from deleted)
set @Acton=@Acton+2

if(@Action=1) -- Only insert

if(@Action=3) -- Only Update
begin
IF (UPDATE([First_Name]) OR UPDATE([Last_Name]) OR UPDATE([JobCode]) OR UPDATE([Inactive]))
Begin

End
end

if(@Action=2) -- Only Delete
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.