您好,欢迎访问三七文档
Oracle数据库技术触发器教学目标掌握触发器的概念掌握触发器的定义和使用方法了解在触发器中如何抛出用户自定义异常信息重点及难点触发器定义触发器应用(难点)触发器触发器类似于过程或函数,因为它们都是拥有声明、执行和异常处理过程的带名PL/SQL块。与包类似,触发器必须存储在数据库中并且不能被块进行本地化声明。但是,对于过程而言.可以从另一个块中通过过程调用显式地执行一个过程。同时在调用时可以传递参数。对于触发器而言,当触发事件发生时就会显式地执行该触发器。并且触发器不接受参数。执行触发器的操作就是“点火”(firing)触发器。触发器事件是在数据库表上执行的DML(INSERT、UPDATE或DELETE)操作。触发器可以使用触发器做许多事情,包括1。维护不可能在表创建时刻通过声明性约束进行的复杂的完整性约束限制。2。通过记录所进行的修改以及谁进行了修改来审计表中的信息。3。当表被修改的时候,自动给其他需要执行操作的程序发信号。触发器触发器不可缺少的部件是触发器名、触发事件和触发器主体。1.触发器名触发器名的名字空间不同于其他子程序的名字空间。“名字空间”是可以用作对象名字的合法标识符的集合。过程、包和表的名字空间相同。这就是说,为过程和包赋予相同的名字将是非法的。但是,触发器却使用的是单独的名字空间。这意味着触发器可以使用和表或过程相同的名字。但是,在一个数据模式中,一个名字仅能用于一个触发器。触发器触发器事件决定了触发器的类型。触发器可以按照INSERT、UPDATE或DELETE操作进行定义,并且它们也可以点火进行行操作或语句操作。触发器也可以对多种类型的触发语句点火。触发器的语法结构完整的过程结构如下:CREATEORREPLACETRIGGERtrigger_name{before|after|insteadof}{Insert[ordelete][orupdate[ofcol1,…coln]}on{table_name|view_name}[foreachrow[when(condition)]][DECLARE]BEGIN执行语句段;EXCEPTION异常处理语句段;END;CREATEORREPLACETRIGGERTR_INSERT_UPDATE_GRADE_SCAFTERINSERTORUPDATEOFgradeONSCFOREACHROWBEGINifinsertingthen--插入时触发dbms_output.put_line('Insert');endif;ifupdatingthen--修改Grade时触发dbms_output.put_line('Update');endif;END;注意事项(1)一个FOREACHROW执行指定操作的触发器为操作修改的每一行都调用一次(行级触发器)。若不带该参数则表示该触发器为语句级触发器,语句级触发器只在插入,修改或删除时执行一次,无论插入,修改,删除影响的是单行还是多行。(2)SELECT并不更改任何行,因此不能创建SELECT触发器。(3)触发器和某一指定的表格有关,当该表格被删除时,任何与该表有关的触发器同样会被删除。(4)在一个表上的每一个动作只能有一个触发器与之关联。在行级触发器中使用:new和:old触发语句所处理的每一行都点火一次行级触发器。在触发器的内部,可以访问当前正在被处理的行。这是通过“伪记录”—:old和:new实现的。:old和:new不是真实的记录。尽管从语法上讲,它们的处理方式和记录是一样的,但实际上它们不是,所以它们就被称为伪记录。它们的类型是:Triggering_table%rowtype在行级触发器中使用:new和:oldINSERT语句没有对:old进行定义,DELETE语句没有对:new进行定义。如果在INSERT中使用了:old或者在DELETE中使用:new,PL/SQL编译器将不会产生错误。但是它们的取值都将是NULL。注意:尽管:new和:old在语法上被作为R0WTYPE的记录进行处理,但是实际上它们并不是记录。结果,许多通常对记录是有效的操作对于:new和:old是无效的。Instead-of触发器PL/SQL提供了另外一种触发器。Instead-of触发器仅可以定义在视图上,并且它们可以替代点火它们的DML语句进行点火。Instead-of触发器必须是行级的。Instead-of触发器是必要的,因为定义触发器的视图可能基于联结(join)并且并非所有的联结都是可更新的。该触发器便可以按照所需的方式执行更新。例如:Instead-of触发器定义下面的视图:createorreplaceviewstu_avgasselectsno,avg(grade)stu_avgfromscgroupbysno;若执行下面语句:deletefromstu_avgwheresno='001';则报错:ORA-01732:此视图的数据操纵操作非法Instead-of触发器创建触发器:createorreplacetriggerstu_avg_deleteinsteadofdeleteonstu_avgforeachrowbegindeletefromscwheresno=:old.sno;end;再执行删除语句,则删除成功。对触发器的限制触发器的主体是一个PL/SQL块。在PL/SQL块中可以使用的所有语句在触发器主体中都是合法的,但是要受到下面限制的约束:1.触发器不能使用事务控制语句:COMMIT,ROLLBACK或SAVEPOINT。触发器作为触发语句执行的一部分被点火,它和触发语句在同一个事务中。当触发语句被提交或撤回提交时,触发器的操作也相应被提交或撤回提交。2.由触发器主体调用的任何过程或函数都不能使用事务控制语句。3.触发器主体不能声明任何LONG或LONGRAW变量。而且,:new和:old不能指向定义触发器的表中的LONLONG或LONGRAW列。4.触发器主体可以访问的表有所限制。根据触发器类型以及在表上的约束限制的不同,表可能也会变化。查询,删除和禁止触发器在user_triggers视图中可以查询触发器:select*fromuser_triggerswheretrigger_name=upper('stu_avg_delete');删除触发器:Droptriggerstu_avg_delete;禁止和打开触发器:altertriggerstu_avg_deletedisable|enable;查询,删除和禁止触发器禁止和打开一个表的所有触发器:altertablerenable|disablealltriggers;当包或者子程序存储在数据字典中时,存储的除了该对象的源代码还有经过编译的p-code。但是对于触发器就不是这样的。在数据字典中唯一存储的是触发器的源代码,而不是p-code。结果,每次当从数据字典中重新读出触发器时,必须要进行编译。触发器点火次序当DML语句被执行时就会点火触发器。下面给出了执行DML语句的顺序:1)执行BEFORE语句级触发器(如果有的话)2)对于受语句影响的每一行:a.执行BEFORE行级触发器(如果有的话)b.执行DML语句。c.执行AFTER行级触发器(如果有的话)3)执行AFTER语句级触发器(如果有的话)触发器实例CREATEORREPLACETRIGGERai_org_trigAFTERINSERTONorg_tabFOREACHROWBEGINUPDATEsec_hrc_auditSETnum_rows=num_rows+1WHEREhrc_code=:NEW.hrc_code;IF(SQL%NOTFOUND)THENINSERTINTOsec_hrc_auditVALUES(:NEW.hrc_code,1);ENDIF;END;CREATEORREPLACETRIGGERai_org_trig_statementAFTERINSERTONorg_tabBEGINFORidxIN(SELECThrc_code,COUNT(*)cntFROMorg_tabGROUPBYhrc_code)LOOPUPDATEsec_hrc_auditSETnum_rows=idx.cntWHEREhrc_code=idx.hrc_code;IF(SQL%NOTFOUND)THENINSERTINTOsec_hrc_auditVALUES(idx.hrc_code,idx.cnt);ENDIF;ENDLOOP;END;触发器实例变化表触发器主体可以访问的表和列上有一些限制。在定义这些限制以前,必须先要认识变化表和限制表。“变化表”是被DML语句正在修改的表。对于触发器而言,它就是定义触发器的表。需要作为DELETECASCADE参考完整性限制的结果进行更新的表也是变化的。DELETECASCADE:级联删除altertablescaddconstraintfk_sc_snoforeignkey(sno)referencesstudent(sno)ondeletecascade;限制表“限制表”是可能需要对参考完整性限制执行读操作的表。比如,对于SC表上的操作进行触发器定义时,SC为变化表,Student和Course表为限制表。(假设SC表上定义了两个外建)行级触发器主体中的SQL语句不允许进行:1。读取或修改触发语句的任何变化表。这些表也包括触发表自己。2。读取或修改触发表的限制表中的主键、唯一值列或外键列。但是如果需要的话,可以修改其他的列。这些限制法则适用于所有的行级触发器。仅当在执行DELETECASCADE操作时启动语句触发器时,它们才适用于语句触发器。行级触发器主体中的SQL语句不允许进行:如果INSERT语句仅影响一个行,那么该行的BEFORE行触发器将不会将触发表作为变化表进行处理。这是行级触发器可以从触发表中执行读或修改操作的唯一可能的情况。象下面这样的语句:INSERTINTOT1SELECT…会始终将触发表作为变化表处理,甚至尽管子查询仅返回一行。完成:1、当向SC表插入数据时,修改(或添加)SC_NUMBER(包括学生学号和选课门数两列)表格中的数据。2、当删除SC表中数据时,修改(或添加)SC_NUMBER中的数据。3、当修改SC表中数据时,若修改的是学号,则对应修改SC_NUMBER表中的选课门数,否则打印“某某(学生姓名)的学生选课信息已经修改”信息。触发器课堂练习1消除变化表错误触发表仅仅对于行级触发器是变化的。这就是说,我们不能在行级触发器中查询它,但是可以在语句级触发器中查询它。但是,我们不能简单地将行级触发器转换为语句触发器.因为我们需要在触发器主体中使用:new,:old的取值。解这个问题的方法是创建两个触发器:一个行级触发器,另一个是语句级触发器。在行级触发器中,我们记录:new,:old的取值,但是不对该表进行查询。在语句级触发器中执行查询并使用行级触发器记录下的数值。我们如何记录这个数值呢?最好的方法是使用包。思考Oracle提供了执行“级联删除”(deletecascade)的功能。进行级联删除时.当从一个父表(Parenttable)中删除了一个行,那么通过外键依赖于父表的子表(childtable)中的相关的行也会被删除。但是,没有缺省实现的级联更新(updatecascade)。通过生成支持级联更新所需要的包和触发器同时又不违反声明的参考完整性限制,可以完成该功能。如何实现?约束约束的检查功能立即执行的约束(Immediateconstraints)语句执行完后立即检查是否违背完整性约束延迟执行的约束(Deferredconstrainsts)完整性检查延迟到整个事务执行结束后进行创建和删除约束示例Altertablescaddconstraintfk_sc_snoforeignkey(sno)referencesstudent(sno)deferrable;--定义该
本文标题:8触发器.
链接地址:https://www.777doc.com/doc-2893247 .html