Тригер оновлення 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()- тестує лише, якщо стовпець з’являється у списку оновлень, і завжди відповідає дійсності для вставок. Він не перевіряє, чи змінилося значення стовпця, оскільки у вас може бути більше одного рядка, де деякі значення змінилися, а деякі - ні.
Микола Марковинович

Відповіді:


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

Коли ви використовуєте команду оновлення для таблиці SCHEDULEта встановіть QtyToRepairстовпець на нове значення, якщо нове значення дорівнює старому значенню в одному або декількох рядках, рішення 1 оновить усі оновлені рядки в таблиці розкладу, але рішення 2 оновить лише рядки розкладу, коли старе значення не дорівнює новому значення.


Вибачте, що не згадуєте, що це був SQLServer. Мені потрібно було скористатися видаленою таблицею. Я закінчив писати до окремої таблиці (для підтримки історії).
Вальтер де Йонг

9
Підхід №2 краще, якщо ви не хочете, щоб ваш тригер спрацьовував, якщо стовпець змінюється на одне значення.
Неоліск

2
Я думаю, що мені може щось не вистачати - але підхід №1 не буде працювати, оскільки це після оновлення, тому поточний рядок завжди матиме те саме значення, що і рядок, що вставляє. Ви повинні приєднатися до видалених, якщо ви користуєтесь після оновлення
Rob

5
@Rob Заява "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
Я вважаю це корисним тому, що приєднання 2-х сполук між відповіддю вище ніколи не працювало через те, де критерії, які 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

Це чудово працює

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.