T-Sql

T-SQL 觸發器如何僅在實際更改時觸發?

  • July 29, 2019

在 UPDATE 和 INSERT 上有一個表觸發器,可以將一行添加到另一個表中。如果更改了四列中的一列,則只需添加一行。我嘗試使用 IF UPDATE(col) 來測試更改,但它有一個盲點。它只測試一些值進來。我需要更深入,我需要比較舊值和新值以查看是否發生了真正的變化。它必須與 INSERT 和 UPDATE 一起使用。

在 UPDATE 的情況下,這很容易,因為插入和刪除的表都有我可以在觸發器中比較的值。但是,對於 INSERT,只有插入表具有值。因為我需要這一切都在同一個觸發器中,我該如何處理那個 INSERT 案例?

這是我要修改的觸發器的腳本:

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

您可以使用 EXCEPT 集合運算符處理 INSERT 和 UPDATE。如果 EXISTS 只是一個 INSERT,或者它是一個對這些列中的任何一個具有不同值的 UPDATE,則 EXISTS 只會評估為 TRUE。

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

如果更新可能影響多行,您必須防止兩件事:

  1. 我們想考慮在相似行之間交換值的更新。如果有兩個 John Smith 需要更新其 JobCodes(第一個 John 從 1 到 2;第二個 John 從 2 到 1),我們需要小心地說他們都已更新。
  2. 我們只想將更改的行記錄在AT_Person_To_Push. 如果更新了 5 行,但僅以我們關心的方式更新了 2 行,那麼我們只需要處理 2 相關行。

這是我將如何處理它:

  1. Left join insertedto deleted,因為inserted將有用於插入和更新的行,而deleted只有用於更新的行。
  2. 使用EXISTSwithEXCEPT查找inserted值與值不同的行deleted。您不能使用i.First_Name != d.First_Name OR i.Last_Name != d.Last_Name...,因為當觸發器正在處理 INSERT 時,已刪除的表將為空(並且 LEFT JOIN 將返回空值)。
  3. 僅將受影響的行插入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

引用自:https://dba.stackexchange.com/questions/243347