一个表上的多个触发器执行顺序问题

一、触发器基础 

1、触发器使用  
     可以定义一个无论何时用insert语句向表中插入数据时都会执行的触发器。    
     当触发insert触发器时,新的数据行就会被插入到触发器表和inserted表中。inserted表是一个逻辑表,它包含了已经插入的数据行的一个副本。inserted表包含了insert语句中已记录的插入动作。inserted表还允许引用由初始化insert语句而产生的日志数据。触发器通过检查inserted表来确定是否执行触发器动作或如何执行它。inserted表中的行总是触发器表中一行或多行的副本。    
    日志记录了所有修改数据的动作(insert、update和delete语句),但在事务日志中的信息是不可读的。然而,inserted表允许你引用由insert语句引起的日志变化,这样就可以将插入数据与发生的变化进行比较,来验证它们或采取进一步的动作。也可以直接引用插入的数据,而不必将它们存储到变量中。   
    
2、delete触发器的工作过程    
     当触发delete触发器后,从受影响的表中删除的行将被放置到一个特殊的deleted表中。deleted表是一个逻辑表,它保留已被删除数据行的一个副本。deleted表还允许引用由初始化delete语句产生的日志数据。     
使用delete触发器时,需要考虑以下的事项和原则:     
(1)、当某行被添加到deleted表中时,它就不再存在于数据库表中;因此,deleted表和数据库表没有相同的行。    
(2)、创建deleted表时,空间是从内存中分配的。deleted表总是被存储在高速缓存中。     
(3)、为delete动作定义的触发器并不执行truncate   table语句,原因在于日志不记录truncate   table语句。    
   
   
3、instead   of触发器的工作过程    
     可以在表或视图上指定instead   of触发器。执行这种触发器就能够替代原始的触发动作。instead   of触发器扩展了视图更新的类型。对于每一种触发动作(insert、update或   delete),每一个表或视图只能有一个instead   of触发器。    
     instead   of触发器被用于更新那些没有办法通过正常方式更新的视图。例如,通常不能在一个基于连接的视图上进行delete操作。然而,可以编写一个instead   of   delete触发器来实现删除。上述触发器可以访问那些如果视图是一个真正的表时已经被删除的数据行。将被删除的行存储在一个名为deleted的工作表中,就像after触发器一样。相似地,在update  instead   of触发器或者insert   instead   of触发器中,你可以访问inserted表中的新行。    
     不能在带有with   check   option定义的视图中创建instead   of触发器。    
   
   
 4、update触发器的工作过程    
      可将update语句看成两步操作:即捕获数据前像(before   image)的delete语句,和捕获数据后像(after   image)的insert语句。当在定义有触发器的表上执行update语句时,原始行(前像)被移入到deleted表,更新行(后像)被移入到inserted表。    
      触发器检查deleted表和inserted表以及被更新的表,来确定是否更新了多行以及如何执行触发器动作。    
      可以使用if   update语句定义一个监视指定列的数据更新的触发器。这样,就可以让触发器容易的隔离出特定列的活动。当它检测到指定列已经更新时,触发器就会进一步执行适当的动作,例如发出错误信息指出该列不能更新,或者根据新的更新的列值执行一系列的动作语句。  

二、触发器执行顺序

 1、典型问题描述: 有多个触发器tg1,tg2,tg3,都是update触发,系统是按照名称排序tg1->tg2->tg3的顺序触发,还是同时触发? 

2、指定第一个和最后一个触发器  
     可将与表相关联的after 触发器之一指定为每个 insert、delete和update 触发动作执行的第一个或最后一个after 触发器。在第一个和最后一个触发器之间激发的after触发器将按未定义的顺序执行。   
     若要指定   after   触发器的顺序,请使用   sp_settriggerorder   存储过程。可用的选项有:     
    sp_settriggerorder [ @triggername = ] '[ triggerschema. ] triggername' , [ @order = ] 'value' , [ @stmttype = ] 'statement_type' [ , [ @namespace = ] { 'DATABASE' | 'SERVER' | NULL } ] Arguments [ @triggername = ] '[ triggerschema. ] triggername' Is the name of the trigger and the schema to which it belongs, if applicable, whose order is to be set or changed. [triggerschema.]triggername is sysname. If the name does not correspond to a trigger or if the name corresponds to an INSTEAD OF trigger, the procedure returns an error. triggerschema cannot be specified for DDL or logon triggers. [ @order = ] 'value' Is the setting for the new order of the trigger. value is varchar(10) and it can be any one of the following values. Important: The First and Last triggers must be two different triggers. Value Description First Trigger is fired first. Last Trigger is fired last. None Trigger is fired in undefined order. [ @stmttype = ] 'statement_type' Specifies the SQL statement that fires the trigger. statement_type is varchar(50) and can be INSERT, UPDATE, DELETE, LOGON, or any Transact-SQL statement event listed in DDL Events. Event groups cannot be specified. A trigger can be designated as the First or Last trigger for a statement type only after that trigger has been defined as a trigger for that statement type. For example, trigger TR1 can be designated First for INSERT on table T1 if TR1 is defined as an INSERT trigger. The Database Engine returns an error if TR1, which has been defined only as an INSERT trigger, is set as a First, or Last, trigger for an UPDATE statement. For more information, see the Remarks section. @namespace = { 'DATABASE' | 'SERVER' | NULL } When triggername is a DDL trigger, specifies whether triggername was created with database scope or server scope. If triggername is a logon trigger, SERVER must be specified. For more information about DDL trigger scope, see Designing DDL Triggers. If not specified, or if NULL is specified, triggername is a DML trigger. Return Code Values 0 (success) and 1 (failure)  

     第一个     
  指定该触发器是为触发操作激发的第一个   after   触发器。  
   
  最后一个    
  指定该触发器是为触发操作激发的最后一个   after   触发器。  
   
  无    
  指定触发器的激发没有特定的顺序。主要用于重新设置第一个或最后一个触发器。  
   
  以下是使用   sp_settriggerorder   的示例:  
   
  sp_settriggerorder   @triggername   =   'mytrigger',   @order   =   'first',   @stmttype   =   'update'  
   
   

  注意: 第一个和最后一个触发器必须是两个不同的触发器。  
   
 3、可能同时在表上定义了insert、update 和delete触发器。每种语句类型可能都有自己的第一个和最后一个触发器,但它们不能是相同的触发器。  
   
  如果为某个表定义的第一个或最后一个触发器不包括触发操作,如 for   update、for  delete 或for insert,则缺少的操作将没有第一个或最后一个触发器。  
   
  不能将   instead   of 触发器指定为第一个或最后一个触发器。在对基础表进行更新前激发instead   of 触发器。然而,如果由   instead   of   触发器对基础表进行更新,则这些更新将发生于在表上定义触发器(包括第一个触发器)之后。例如,如果视图上的   instead   of   触发器更新基表并且该基表包含三个触发器,则该三个触发器在   instead   of   触发器插入数据之前激发。有关更多信息,请参见指定触发器何时激发。  
   
  如果alter trigger  语句更改了第一个或最后一个触发器,则将除去 first   或 last 特性,并且顺序值将设置为 none;必须用   sp_settriggerorder   重置此顺序。    
  objectproperty   函数使用属性   execisfirsttrigger   和   execislasttrigger   报告触发器的顺序是第一个还是最后一个。  
   
  复制将为本身是即时更新订户或排队更新订户的任何表自动生成第一个触发器。复制要求它的触发器是第一个触发器。如果尝试使具有第一个触发器的表成为即时更新订户或排队更新订户,复制将引发错误。如果使表成为即时更新订户或排队更新订户之后使用户定义触发器成为第一个触发器,则sp_settriggerorder 会返回一个错误。如果在复制触发器上使用 alter,或使用   sp_settriggerorder   将复制触发器更改为最后触发器或无触发器,则订阅将不能正确工作。  

两个触发器完全相同吗,如果全部相同,会先执行后建立的触发器。执行的顺序与建立的顺序相反。
(原文地址:http://www.cnblogs.com/netguid/archive/2007/03/29/692241.aspx)

你可能感兴趣的:(Sqlserver,&Oracle)