【问题标题】:SQL Server 2008 R2 Trigger multiple rows in a single batch update issueSQL Server 2008 R2 在单个批量更新问题中触发多行
【发布时间】:2013-01-27 18:16:40
【问题描述】:

我在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 的行为方式。有人看到同样的东西吗?

【问题讨论】:

  • 为什么还需要所有这些表? --UPDATE PER_ID 下的查询看起来不错。为什么你不能单独使用它?
  • @usr 感谢您的快速回复。如果我在 l.ORG_ID = i.ORG_ID 和 l.StaffType = i 上使用 " update l set PER_ID = 1, UpdatedOn = GETDATE() from dbo.tblOrgStaffAssocLastUpadate l inner join [dbo].[inserted] i,它将无法正常工作.StaffType 内部连接 ​​[dbo].[deleted] d on i.ORG_ID = d.ORG_ID 和 i.StaffType = d.StaffType 其中 isnull(i.PER_ID, cast(cast(0 as binary) as uniqueidentifier)) isnull (d.PER_ID, cast(cast(0 as binary) as uniqueidentifier))"。仅更新一行。其余行根本不更新
  • @usr 如果我插入 " select l.* from dbo.tblOrgStaffAssocLastUpadate l inner join [dbo].[inserted] i on l.ORG_ID = i.ORG_ID and l,我什至可以看到返回的多行.StaffType = i.StaffType 内部连接 ​​[dbo].[deleted] d on i.ORG_ID = d.ORG_ID 和 i.StaffType = d.StaffType 其中 isnull(i.PER_ID, cast(cast(0 as binary) as uniqueidentifier) ) isnull(d.PER_ID, cast(cast(0 as binary) as uniqueidentifier)) " 在更新语句之前。我很困惑为什么下一个更新语句只更新一行。
  • 不要将代码示例或示例数据放入 cmets - 因为您无法对其进行格式化,所以阅读它非常困难....而是:更新您的问题,编辑它以提供附加信息!谢谢。

标签: sql sql-server sql-server-2008 triggers sql-update


【解决方案1】:

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

这只是UPDATE 上的触发器,因此,总会有一个DELETED 表,其中包含每个更改的行曾经 表中的内容,并且总会有一个@987654325 @ 为每个更改的行包含表中的 将是什么。因此,出于您的目的,您只需要处理这些表之一。未更改的行不在两个表中。

如果这是INSERT 上的触发器,则只有INSERTED 表。同样,DELETE 触发器只有一个DELETED 表。

其次,您似乎认为 NULL=NULL 是真的 - 它不是。语句 NULL=NULL 返回 NULL。 NULLNULL、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

【讨论】:

  • 感谢您的回答。你说得对,我把这个复杂化了,但是复杂的连接应该产生正确的结果,因为 INSERT 和 DELETE 持有同样的东西。对于第二个问题,由于我不认为 N​​ULL=NULL,所以我使用 isnull 函数来检查并转换 null 值以便能够比较。我错过了什么吗?
  • 击败我。它有效吗?如果是这样,您可能已经涵盖了所有内容:-)
猜你喜欢
  • 2014-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多