列が変更された場合にのみ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

回答:


128

あなたの質問には2つの方法があります:

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つまたは複数の行の新しい値が古い値と等しい場合、ソリューション1はスケジュールテーブルのすべての更新された行を更新しますが、ソリューション2は古い値が新しいと等しくないスケジュール行のみを更新します値。


それがSQLServerであることを言及しなかったことについて申し訳ありません。削除したテーブルを使用する必要がありました。(履歴を維持するために)別のテーブルに書き込むことになりました。
Walter de Jong

9
列が同じ値に変更されている場合にトリガーを起動させたくない場合は、アプローチ#2の方が適しています。
Neolisk

2
何か不足している可能性があると思いますが、これは更新後なので、アプローチ1は機能しません。したがって、現在の行は常に挿入する行と同じ値になります。更新後に使用する場合は、削除に参加する必要あります
Rob

5
@Rob "IF UPDATE"ステートメントは、クエリの一部として更新された列の列リストにアクセスできるプロシージャを呼び出しているため、以前の値を知る必要はありません。(私達は私達の環境でこれに遭遇し、 "AFTER UPDATE"句に関係なく "IF UPDATE"が尊重されることを確認しました)
TChadwick '18

3
なぜinserted2番目のクエリでテーブルを結合するのですか?それはテーブル自体と同じである必要がありますね?
teran 2018

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 2016

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

それはうまくいきます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.