SQL更新仅在修改列时触发


101

通过查看其他示例,我想出了以下内容,但它似乎并没有达到我想要的效果:我希望它仅在QtyToRepair值已更新的情况下才更新修改后的信息...但是它不这样做那。

如果我注释掉哪里,那么在每种情况下都会更新修改后的信息。正如我所说,其他例子使我感到乐观。任何线索表示赞赏。谢谢。

沃尔特

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

8
关于的警告update()-它仅测试列是否出现在更新列表中,并且对于插入始终为true。它不检查列值是否已更改,因为您可能有多个行,其中某些值已更改,而有些则未更改。
NikolaMarkovinović2012年

Answers:


128

您有两种方式提出问题:

1-在触发器中使用更新命令。

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-在插入表和已删除表之间使用联接

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

当您对表使用update命令SCHEDULE并将QtyToRepairColumn 设置为新值时,如果新值等于一行或多行中的旧值,则解决方案1更新Schedule表中的所有更新行,而解决方案2仅更新旧值不等于new的计划行值。


对不起,没有提到它是SQLServer。我需要使用已删除的表。我最终写了一个单独的表(以保持历史记录)。
沃尔特·德钟

9
如果您不希望在将列更改为相同值时触发触发器,则方法#2更好。
Neolisk

2
我想我可能会丢失一些东西,但是方法1无效,因为这是更新之后进行的,因此当前行将始终具有与插入行相同的值。你必须,如果你更新后使用连接到删除
罗布

5
@Rob“ IF UPDATE”语句正在调用一个过程,该过程可以访问作为查询一部分而更新的列的列列表,因此不需要知道先前的值。(我们只是在我们的环境中遇到了这种情况,并确认无论“ AFTER UPDATE”子句如何,“ IF UPDATE”都是受尊重的)
TChadwick

3
为什么inserted在第二个查询中加入表?它应该与表本身相同,不是吗?
特兰

22

fyi我最终得到的代码是:

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

1
我发现这很有用,因为由于where条件永远不会触发/匹配(因为第一个条件永远不会为真),因此上述答案的2-Use Join之间无法使用WHERE S.QtyToRepair <> I.QtyToRepair AND D.QtyToRepair <> I.QtyToRepair -插入的表始终与实际表值匹配。对我来说,使用`WHERE I.QtyToRepair <> D.QtyToRepair`是关键。此外,还有IF UPDATE (field)多个触发器触发的帮助。
Firegarden

13

首先应检查是否QtyToRepair已更新。

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

6

您要执行以下操作:

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

每当记录更新时,都会“删除”记录。这是我的示例:

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

工作正常

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.