仅在进行实际更改时触发的 T-SQL 触发器如何?

Wil*_*llG 9 trigger 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
Run Code Online (Sandbox Code Playgroud)

SQL*_*tor 18

您可以使用 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...
Run Code Online (Sandbox Code Playgroud)

  • 在更新中“交换”2 行的情况下,这不起作用。如果我们有两个 John Smith 需要更新他们的工作代码(第一个 John 从 1 到 2;第二个 John 从 2 到 1) - 这表示没有发生更新。 (2认同)
  • @StevenHibble - 虽然可能发生这种情况的可能性有多大?这种情况可以通过在上面的 Select 语句中包含 PK 列来轻松解决。 (2认同)

Ste*_*ble 5

如果更新可能影响多行,您必须防止两件事:

  1. 我们要考虑在相似行之间交换值的更新。如果有两个 John Smith 需要更新其 JobCode(第一个 John 从 1 到 2;第二个 John 从 2 到 1),我们需要小心地说他们都已更新。
  2. 我们只想将更改的行记录在AT_Person_To_Push. 如果更新了 5 行,但只有 2 行以我们关心的方式更新,那么我们只需要处理 2 相关行。

我的处理方法如下:

  1. 左连接inserteddeleted,因为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
Run Code Online (Sandbox Code Playgroud)