【问题标题】:Return early from a trigger in order to skip the logic从触发器提前返回以跳过逻辑
【发布时间】:2019-09-30 18:31:42
【问题描述】:

我想跳过在表更新时调用的触发器。我知道如果更新行的 UserID 低于某个 ID,我可以跳过它。

inserted 表可以有多行,什么时候会有多行?由于触发器在更新时触发,因此不会为更新中的每一行调用触发器吗?

下面的 SQL 是否正确忽略了触发器。如果 ID 小于 123,我希望触发器只是 RETURN 并跳过它通常会执行的逻辑:

DECLARE @UserID AS INT = (SELECT UserID FROM Inserted)
IF @UserID <= 123
BEGIN
    RETURN
END

【问题讨论】:

  • 如果inserted 表包含一些小于 123 的行和一些大于 123 的行,你希望发生什么?
  • 添加了 where 子句,select * from inserted where userID &gt; 123

标签: sql-server triggers


【解决方案1】:

SQL Server triggers 每条语句触发一次,而不是每行触发一次。而且一条语句可以影响任意数量的行。

因此,您必须执行正常的触发逻辑,并且对任何具有UserId &lt;= 123 的行不采取任何操作。

【讨论】:

  • 我明白了,所以DECLARE @UserID AS INT = (SELECT UserID FROM Inserted) 不会工作,对吧?那我应该做SELECT TOP 1 UserID FROM inserted 吗?
  • 没有。您必须对触发器进行编码,以期望在 Inserted 中有多个行,其中冷的任何子集都有 UserID &lt;= 123
【解决方案2】:

如果您毫无疑问地知道所有正在更新的行都将包含相同的UserID,您可以使用以下方法快捷地退出触发器:

if exists (select 1 from Inserted where UserId <= 123) return;

这可能非常危险,因为如果曾经有一个包含 UserId 123 的混合更新,触发器将不会针对 > 123 运行。请考虑,虽然您的应用可能永远不会这样做,但 DBA 可能来自SSMS 手动更正一些数据。

这种情况的正确处理方法如下:

declare @Id int, @UserId int;
declare @Rows table (Id int, UserId int);

insert into @Rows (Id, UserId)
  select Id, UserId from Inserted;

while exists (select 1 from @Rows) begin
  select top 1 @Id = Id, @UserId = UserId from @Rows;
  if @UserId > 123 begin
    -- Do stuff
  end
  delete from @Rows where Id = @Id;
end

应该注意的是,您应该尽可能避免这种基于逐行的活动,因为它是一种反数据库模式,可能会导致性能问题。理想情况下,所有数据库操作都将基于设置。

【讨论】:

    猜你喜欢
    • 2022-10-07
    • 1970-01-01
    • 1970-01-01
    • 2019-07-19
    • 2019-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多