SQL-Update-Trigger nur, wenn die Spalte geändert wird

101

Wenn ich mir andere Beispiele ansehe, habe ich Folgendes gefunden, aber es scheint nicht so zu funktionieren, wie ich es gerne hätte: Ich möchte, dass die geänderten Informationen nur aktualisiert werden, wenn der QtyToRepairWert aktualisiert wurde ... aber das funktioniert nicht Das.

Wenn ich das Wo auskommentiere, werden die geänderten Informationen in jedem Fall aktualisiert. Wie gesagt, andere Beispiele haben mich optimistisch gemacht. Alle Hinweise geschätzt. Vielen Dank.

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
Walter de Jong
quelle
8
Eine Warnung zu update()- Sie testet nur, ob die Spalte in der Aktualisierungsliste angezeigt wird, und gilt immer für Einfügungen. Es wird nicht überprüft, ob sich der Spaltenwert geändert hat, da möglicherweise mehr als eine Zeile vorhanden ist, wobei sich einige Werte geändert haben und andere nicht.
Nikola Markovinović

Antworten:

128

Sie haben zwei Möglichkeiten für Ihre Frage:

1- Verwenden Sie den Update-Befehl in Ihrem 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- Verwenden Sie Join zwischen eingefügter Tabelle und gelöschter Tabelle

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

Wenn Sie den Befehl update für die Tabelle verwenden SCHEDULEund die QtyToRepairSpalte auf einen neuen Wert setzen und der neue Wert dem alten Wert in einer oder mehreren Zeilen entspricht, aktualisiert Lösung 1 alle aktualisierten Zeilen in der Zeitplantabelle, aber Lösung 2 aktualisiert nur Zeitplanzeilen, deren alter Wert nicht gleich neu ist Wert.

mehdi lotfi
quelle
Es tut uns leid, dass Sie nicht erwähnt haben, dass es sich um SQLServer handelt. Ich musste die gelöschte Tabelle verwenden. Am Ende schrieb ich an eine separate Tabelle (um einen Verlauf zu führen).
Walter de Jong
9
Ansatz 2 ist besser, wenn Sie nicht möchten, dass Ihr Trigger ausgelöst wird, wenn die Spalte auf denselben Wert geändert wird.
Neolisk
2
Ich glaube, mir fehlt möglicherweise etwas - aber Ansatz 1 würde nicht funktionieren, da dies nach dem Update erfolgt und die aktuelle Zeile immer den gleichen Wert wie die einfügende Zeile hat. Sie müssen gelöscht werden, wenn Sie nach dem Update verwenden
Rob
5
@Rob Die Anweisung "IF UPDATE" ruft eine Prozedur auf, die Zugriff auf eine Spaltenliste von Spalten hat, die als Teil der Abfrage aktualisiert wurden und daher die vorherigen Werte nicht kennen müssen. (Wir sind gerade in unserer Umgebung darauf
gestoßen
3
Warum verbinden Sie die insertedTabelle in der zweiten Abfrage? es sollte das gleiche sein wie der Tisch selbst, nicht wahr?
Teran
22

fyi Der Code, mit dem ich endete:

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
Walter de Jong
quelle
1
Ich fand dies hilfreich, weil die obige Antwort 2-Use Join zwischen nie funktioniert hat, da Kriterien WHERE S.QtyToRepair <> I.QtyToRepair AND D.QtyToRepair <> I.QtyToRepairnie ausgelöst / abgeglichen wurden, da die ersten Kriterien nie wahr waren - die eingefügte Tabelle stimmte immer mit dem tatsächlichen Tabellenwert überein. Die Verwendung von "WHERE I.QtyToRepair <> D.QtyToRepair" war der Schlüssel für mich. Auch die IF UPDATE (field)Hilfe von mehreren Auslösern löst aus.
Firegarden
13

Man sollte zuerst prüfen, ob QtyToRepairaktualisiert wird.

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
hgulyan
quelle
6

Sie möchten Folgendes tun:

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

Bitte beachten Sie, dass dieser Trigger jedes Mal ausgelöst wird, wenn Sie die Spalte aktualisieren, unabhängig davon, ob der Wert gleich ist oder nicht.

Carlos Vergara
quelle
2

Immer wenn ein Datensatz aktualisiert wurde, wird ein Datensatz "gelöscht". Hier ist mein Beispiel:

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

Es funktioniert gut

Mohamed Yazeer
quelle