问题
我有一个创建在表上的触发器,当对表执行一个INSERT,DELETE或者UPDATE语句时,这个触发器将被激活执行。我想在一个特定的语句上阻止触发器被激活,而当执行其它语句时触发器仍然保持正常的执行状态。有没有一种方法可以动态做到这些?
专家解答
在某些时候,停用触发器是可能需要你去做的事情,尤其是你在一张表上执行管理员任务时。实现这点的最好方法是使用以下的命令去完全停用触发器。
ALTER TABLE Table_Name DISABLE TRIGGER Trigger_Name
尽管如此,如果你只想在一个特殊的语句上停用触发器,然而没有一种默认的机制来实现这一点,除非你开发一种自己的可编程的方法。使用这种方法只在某个特定语句上停用触发器而这个触发器在其他同时点击服务器的语句上继续被激活执行。
即使有很多种方式去实现它,主要的逻辑在于传递一些信号给触发器,告诉触发器你不需要激活它执行。
使用一张临时表
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)实现这个任务最简单的方法是在你执行会激活触发器的语句之前先创建一张临时表。现在这个触发器将检查临时表存在与否,并且,如果这张临时表存在,那么触发器将会返回并且不执行代码,否则它将会像平常一样执行它的代码。
为了看看执行过程,让我们来运行以下的语句来创建一张表和一个触发器。
USEAdventureWorks;
GO
--creatingthetableinAdventureWorksdatabase
IFOBJECT_ID('dbo.Table1')ISNOTNULL
DROPTABLEdbo.Table1
GO
CREATETABLEdbo.Table1(IDINT)
GO
--Creatingatrigger
CREATETRIGGERTR_TestONdbo.Table1FORINSERT,UPDATE,DELETE
AS
IFOBJECT_ID('tempdb..#Disable')ISNOTNULLRETURN
PRINT'TriggerExecuted'
--Actualcodegoeshere
--Forsimplicity,Ididnotincludeanycode
GO
如果你不想触发器在一个语句上被激活执行,那么通过在你的语句中创建临时表让触发器知道这一点。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/) CREATETABLE#Disable(IDINT)
--Actualstatement
INSERTdbo.Table1VALUES(600)
DROPTABLE#Disable
你会发现INSERT语句并没有激活触发器,并且由于创建的临时表在本地会话中,触发器不能通过其他会话绕过。
这个过程可能比较顺利,但是必须使用Tempdb数据库来创建一张临时表,接着删除这张临时表,这将导致资源浪费,不过这种情况是可以避免的。
使用Context_Info( )
完成这个任务的另一种方法是使用会话中的上下文信息。上下文信息是属于某个会话的一个变量。它的值可以通过SET Context_Info更改。
触发器看起来通常像这样:
USEAdventureWorks;
GO
--creatingthetableinAdventureWorksdatabase
IFOBJECT_ID('dbo.Table1')ISNOTNULL
DROPTABLEdbo.Table1
GO
CREATETABLEdbo.Table1(IDINT)
GO
--Creatingatrigger
CREATETRIGGERTR_TestONdbo.Table1FORINSERT,UPDATE,DELETE
AS
DECLARE@CinfoVARBINARY(128)
SELECT@Cinfo=Context_Info()
IF@Cinfo=0x55555
RETURN
PRINT'TriggerExecuted'
--Actualcodegoeshere
--Forsimplicity,Ididnotincludeanycode
GO
如果你想阻止触发器执行,那么你可以运行下面的代码:
SETContext_Info0x55555
INSERTdbo.Table1VALUES(100)
执行INSERT语句之前,上下文信息设置成一个值。在这个触发器中,我们首先查看上下文信息的值与声明的值是否一样。如果是一样的,那么这个触发器将会仅做返回操作而不执行它的代码。要不然这个触发器将会被激活执行。