1

我以这种方式在 SQL Server 2008 R2 中实现了触发器 -

    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。只有一排,它工作正常。但是,对于一批发送的多行,它仅在 tblOrgStaffAssocLastUpadate 更新一行,而 tblOrgStaffAssoc 更新了多行。

当我使用中间表 _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))

仅更新一行。其余行根本不更新。即使我可以看到返回多行,如果我使用

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)) 

就在更新声明之前。这就是我完全困惑的地方,为什么下一个更新语句只更新一行,为什么只有永久表可以持久更新所有行,但不能持久表和表变量。

更新的问题 -

由于多个更新行在单个批次中发送到表。似乎触发器的 INSERT 和 DELETE 表只有一个,最后一个仅在我到达“update l”语句时才更新行。在此之前,它包含多个更新行。当我使用永久表时,我可以看到这一点。我只是不明白 SQL Server 的行为方式。有人看到同样的事情吗?

4

1 回答 1

2

你严重过度复杂化了这一点。您不需要 和 之间的所有这些检查和INSERTED链接DELETED

这只是一个触发器UPDATE,因此,对于每个更改的行,总是有一个DELETED表包含表中的内容,并且对于每个更改的行,总是有一个包含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 回答