1

この方法でSQLServer2008R2にトリガーを実装しました-

    ALTER TRIGGER [dbo].[trgtblOrgStaffAssocLastUpdate] ON [dbo].[tblOrgStaffAssoc]
       AFTER UPDATE
    AS

    IF EXISTS (SELECT i.* FROM INSERTED i inner join deleted d on i.ORG_ID = d.ORG_ID and isnull(i.StaffType, -1111) = isnull(d.StaffType, -1111)
    where i.Deleted = 0
    and (isnull(i.PER_ID, cast(cast(0 as binary) as uniqueidentifier)) <> isnull(d.PER_ID, cast(cast(0 as binary) as uniqueidentifier))          
    ))
    BEGIN

        IF EXISTS (SELECT * FROM DELETED)
        BEGIN   

            --UPDATE PER_ID      
            update l    
            set PER_ID = 1, UpdatedOn =  GETDATE()
            from dbo.tblOrgStaffAssocLastUpadate l inner join [dbo].[inserted] i on l.ORG_ID = i.ORG_ID and l.StaffType = i.StaffType
            inner join [dbo].[deleted] d on i.ORG_ID = d.ORG_ID and i.StaffType = d.StaffType
            where isnull(i.PER_ID, cast(cast(0 as binary) as uniqueidentifier)) <> isnull(d.PER_ID, cast(cast(0 as binary) as uniqueidentifier))          
        END         

END

私の目的は、tblOrgStaffAssocが更新されたときにtblOrgStaffAssocLastUpadateを更新することです。1行だけで、正常に機能します。ただし、1つのバッチで送信される複数の行の場合、tblOrgStaffAssocで複数の行が更新されるのに対し、tblOrgStaffAssocLastUpadateでのみ1つの行が更新されます。

中間テーブル_Insertedおよび_deletedを使用してINSERTEDおよびDELETEDデータをバッファリングし、永続テーブルを使用してこのように更新すると-

 ALTER TRIGGER [dbo].[trgtblOrgStaffAssocLastUpdate] ON [dbo].[tblOrgStaffAssoc]
   AFTER UPDATE
AS

IF EXISTS (SELECT i.* FROM INSERTED i inner join deleted d on i.ORG_ID = d.ORG_ID and isnull(i.StaffType, -1111) = isnull(d.StaffType, -1111)
where i.Deleted = 0
and (isnull(i.PER_ID, cast(cast(0 as binary) as uniqueidentifier)) <> isnull(d.PER_ID, cast(cast(0 as binary) as uniqueidentifier))          
))
BEGIN

    IF EXISTS (SELECT * FROM DELETED)
    BEGIN   
        IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[_inserted]') AND type in (N'U'))
            insert into [dbo].[_inserted]
            select * from inserted 
        else
            select * into [dbo].[_inserted]
            from inserted

        IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[_deleted]') AND type in (N'U'))
            insert into [dbo].[_deleted]
            select * from deleted 
        else
            select * into [dbo].[_deleted]
            from deleted

        --UPDATE PER_ID      
        update l    
        set PER_ID = 1, UpdatedOn =  GETDATE()
        from dbo.tblOrgStaffAssocLastUpadate l inner join [dbo].[_inserted] i on l.ORG_ID = i.ORG_ID and l.StaffType = i.StaffType
        inner join [dbo].[_deleted] d on i.ORG_ID = d.ORG_ID and i.StaffType = d.StaffType
        where isnull(i.PER_ID, cast(cast(0 as binary) as uniqueidentifier)) <> isnull(d.PER_ID, cast(cast(0 as binary) as uniqueidentifier))          
    END

END

正常に動作します。#insertedまたはテーブル変数@insertedを使用するように永続テーブル_Insertedを変更しても機能しません。

どうやらパーマネントテーブルを使用するのは良い考えではありません。トリガーがこのようにどのように機能するのかわかりません。誰か助けてもらえますか?

ありがとう

@usrのコメントに答えるために編集-

使用すると正しく動作しません-

update l set PER_ID = 1, UpdatedOn = GETDATE() from dbo.tblOrgStaffAssocLastUpadate l inner join [dbo].[inserted] i on l.ORG_ID = i.ORG_ID and l.StaffType = i.StaffType inner join [dbo].[deleted] d on i.ORG_ID = d.ORG_ID and i.StaffType = d.StaffType where isnull(i.PER_ID, cast(cast(0 as binary) as uniqueidentifier)) <> isnull(d.PER_ID, cast(cast(0 as binary) as uniqueidentifier))

1行だけが更新されます。残りの行はまったく更新されません。使用すると複数の行が返されるのを見ることができますが

select l.* from dbo.tblOrgStaffAssocLastUpadate l inner join [dbo].[inserted] i on l.ORG_ID = i.ORG_ID and l.StaffType = i.StaffType inner join [dbo].[deleted] d on i.ORG_ID = d.ORG_ID and i.StaffType = d.StaffType where isnull(i.PER_ID, cast(cast(0 as binary) as uniqueidentifier)) <> isnull(d.PER_ID, cast(cast(0 as binary) as uniqueidentifier)) 

更新ステートメントの直前。ここで、次の更新ステートメントが1つの行のみを更新する理由と、永続テーブルのみがすべての行の更新を保持できるが、一時テーブルとテーブル変数は保持できない理由を完全に混乱させています。

更新された質問-

複数の更新行が単一のバッチでテーブルに送信されるため。「updatel」ステートメントに到達した時点で、トリガーのINSERTテーブルとDELETEテーブルは1つだけで、最後の1つは行を更新しているようです。その前に、複数の更新行を保持します。パーマネントテーブルを使用すると、それがわかります。SQLServerがこのように動作することを理解していません。誰もが同じことを見ましたか?

4

1 に答える 1

2

あなたはこれをひどく複雑にしすぎています。INSERTEDとの間のこれらすべてのチェックとリンクは必要ありませんDELETED

UPDATEこれはオンのみのトリガーであるため、DELETED変更された行ごとにテーブルに含まれるものを含むテーブルが常に存在し、変更された行ごとにテーブルに含まれるものを含むテーブル常に存在します。したがって、目的のために、これらのテーブルの1つだけを処理する必要があります。変更されていない行はどちらのテーブルにもありません。INSERTED

これがトリガーだった場合INSERT、テーブルのみが存在しINSERTEDます。同様に、DELETEトリガーにはDELETEDテーブルしかありません。

第二に、あなたはNULL=NULLが真であると考えているようです-そうではありません。ステートメントNULL=NULLは、NULLを返します。NULL <> NULL、NULL> = NULLなども同様です。データベースでは、NULLは値ではないことを意味し、値を持たないものは比類のないものです。したがって、whereステートメントも不要です。

だから私はあなたが望むコードは次のとおりだと思います:

ALTER TRIGGER [dbo].[trgtblOrgStaffAssocLastUpdate] ON [dbo].[tblOrgStaffAssoc]
   AFTER UPDATE
AS
   UPDATE l    
   SET PER_ID = 1
      ,UpdatedOn =  GETDATE()
   FROM dbo.tblOrgStaffAssocLastUpadate l
        INNER JOIN
        inserted i ON l.ORG_ID = i.ORG_ID and l.StaffType = i.StaffType
于 2013-01-29T03:52:54.680 に答える