web-dev-qa-db-ja.com

実際の変更でのみ発生するT-SQLトリガーはどのように作成されますか?

別のテーブルに行を追加するテーブルPDATEおよびINSERTのトリガーがあります。 4つの列のいずれかが変更された場合にのみ、行を追加する必要があります。 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
9
WillG

EXCEPTセット演算子を使用すると、INSERTとUPDATEの両方を処理できます。 EXISTSは、単なるINSERTの場合、またはこれらの列のいずれかに異なる値を持つUPDATEの場合にのみ、TRUEと評価されます。

IF EXISTS (
           SELECT First_Name, Last_Name, JobCoe, Inactive FROM inserted
           EXCEPT
           SELECT First_Name, Last_Name, JobCoe, Inactive FROM deleted
          )
BEGIN...
18
SQLRaptor

更新が複数の行に影響を与える可能性がある場合、次の2つのことから保護する必要があります。

  1. 同様の行の間で値を交換する更新を検討します。 JobCodeを更新する必要がある2人のJohn Smithがいる場合(最初のJohnは1から2、2番目のJohnは2から1)、両方が更新されたと言うことに注意する必要があります。
  2. 変更された行のみをAT_Person_To_Pushに記録します。 5つの行が更新されても、気になる方法で2つだけが更新される場合は、関連する2つの行のみを処理する必要があります。

これが私がそれをどう扱うかです:

  1. insertedには挿入と更新の行があり、deletedには更新の行しかないため、inserteddeletedに左結合します。
  2. EXISTSEXCEPTを使用して、inserted値がdeleted値と異なる行を検索します。トリガーがINSERTを処理しているときは、削除されたテーブルが空になるため(そしてLEFT JOINがnullを返すため)、i.First_Name != d.First_Name OR i.Last_Name != d.Last_Name...を使用できません。
  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
2
Steven Hibble

これを試して、

Declare @Acton int=0

If exists (Select 1 from inserted)
set @Acton=1

If exists (Select 1 from deleted)
set @Acton=@Acton+2

if(@Action=1) -- Only insert

if(@Action=3) -- Only Update
begin
IF (UPDATE([First_Name]) OR UPDATE([Last_Name]) OR UPDATE([JobCode]) OR UPDATE([Inactive]))
Begin

End
end

if(@Action=2) -- Only Delete
1
KumarHarsh