T-Sql
T-SQL 觸發器如何僅在實際更改時觸發?
我在 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...
如果更新可能影響多行,您必須防止兩件事:
- 我們想考慮在相似行之間交換值的更新。如果有兩個 John Smith 需要更新其 JobCodes(第一個 John 從 1 到 2;第二個 John 從 2 到 1),我們需要小心地說他們都已更新。
- 我們只想將更改的行記錄在
AT_Person_To_Push
. 如果更新了 5 行,但僅以我們關心的方式更新了 2 行,那麼我們只需要處理 2 相關行。這是我將如何處理它:
- Left join
inserted
todeleted
,因為inserted
將有用於插入和更新的行,而deleted
只有用於更新的行。- 使用
EXISTS
withEXCEPT
查找inserted
值與值不同的行deleted
。您不能使用i.First_Name != d.First_Name OR i.Last_Name != d.Last_Name...
,因為當觸發器正在處理 INSERT 時,已刪除的表將為空(並且 LEFT JOIN 將返回空值)。- 僅將受影響的行插入
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