启用和禁用触发器的替代方法

Posted

技术标签:

【中文标题】启用和禁用触发器的替代方法【英文标题】:Alternative to enable and disable trigger 【发布时间】:2022-01-20 00:43:39 【问题描述】:

对于此示例,是什么? 这是我的触发器,我有一个场景,它不应该被允许直接更新 Table33 中的列 Column33(通过执行查询 UPDATE Table33 SET Column33='123'),但它应该被允许从其他列更新该列正在执行某些计算的触发器。当我在其他触发器中禁用触发器 Triger33,在触发器内部进行更新然后再次启用此触发器时,它会起作用。这个解决方案不好。有没有办法可以给这个触发器设置某种条件,以便它允许不直接的更新,这样我就可以避免在其他触发器中禁用和启用?

create trigger [dbo].[Trigger33]
on [dbo].[Table33]
AFTER UPDATE
as
    if UPDATE(Column33)
    begin
        raiserror('It is not allowed to update Column33 in Table33', 16,1)
        rollback
    end

【问题讨论】:

添加 "AND @@TRIGGER_NESTLEVEL = 1" 能解决问题吗? 您可能还需要检查值是否实际更改:“AND EXISTS(SELECT * FROM INSERTED I JOIN DELETED D ON D.ID = I.ID WHERE I.Column33 D.第 33 列)”。如果需要考虑空值或区分大小写,则比较可能需要稍微复杂一些。 在另一个触发器中设置CONTEXT_INFO,并在这个触发器中检查。 或者使用更现代的session_context 允许触发器彼此聊天。 【参考方案1】:

您可以使用nested triggers 服务器配置选项或NESTED_TRIGGERS 数据库配置选项(对于部分包含的数据库)允许触发器代码全局绕过其他触发器。

例如

EXEC sp_configure 'show advanced options', 1;  
GO  
RECONFIGURE ;  
GO  
EXEC sp_configure 'nested triggers', 0 ;  
GO  
RECONFIGURE;  
GO  
create table t(id int primary key)
create table t2(id int primary key)

go
create trigger te_nope on t2 after insert 
as
begin
  throw 50001, 'nope', 1;
end

go

create trigger t_ins on t after insert
as
begin
  insert into t2(id) select id from inserted 
end

go

insert into t2(id) values (1)  --fails
--Msg 50001, Level 16, State 1, Procedure te_nope, Line 4 [Batch Start Line 32]
--nope

insert into t(id) values (1) --suceeds
--(1 row affected)
--
--(1 row affected)

其他选项包括将秘密推入在内部触发器中检查的 CONTEXT_INFO,或执行检查以修改嵌套触发器的行为的模拟。

【讨论】:

以上是关于启用和禁用触发器的替代方法的主要内容,如果未能解决你的问题,请参考以下文章

Oracle启用和禁用触发器

在 Azure WebJob 中动态启用/禁用触发功能

SQL Server触发器的禁用和启用

用于禁用/启用触发所有的 Postgresql 权限

禁用或启用数据库所有触发器

SQL Server:检查触发器是启用还是禁用?