Oracle超详细笔记10--触发器

匆匆过客 提交于 2019-12-27 14:26:28

一、触发器概述

1.触发器的概念与作用

触发器是一种特殊类型的存储过程,编译后存储在数据库服务器中。

当特定事件发生时,由系统自动调用执行,而不能由应用程序显式地调用执行。

触发器不接受任何参数

触发器主要用于维护那些通过创建表时的声明约束不可能实现的复杂的完整性约束,并对数据库中特定事件进行监控和响应。

 

2.触发器的类型

DML触发器

建立在基本表上的触发器,响应基本表的INSERT,UPDATE,DELETE操作。

INSTEAD OF触发器

建立在视图上的触发器,响应视图上的INSERT,UPDATE,DELETE操作。

系统触发器

建立在系统或模式上的触发器,响应系统事件和DDL(CREATE,ALTER,DROP)操作。

 

3.触发器组成

触发器由触发器头部触发器体两个部分组成,主要包括:

作用对象:触发器作用的对象包括表、视图、数据库和模式。

触发事件:激发触发器执行的事件。如DML、DDL、数据库系统事件等。

触发时间:用于指定触发器在触发事件完成之前还是之后执行。如果指定为AFTER,则表示先执行触发事件,然后再执行触发器;如果指定为BEFORE,则表示先执行触发器,然后再执行触发事件。

触发级别:触发级别用于指定触发器响应触发事件的方式。默认为语句级触发器,即触发事件发生后,触发器只执行一次。如果指定为FOR EACH ROW,即为行级触发器,则触发事件每作用于一个记录,触发器就会执行一次。

触发条件:由WHEN子句指定一个逻辑表达式,当触发事件发生,而且WHEN条件为TRUE时,触发器才会执行。

触发操作:触发器执行时所进行的操作。

 

二、DML触发器

1.DML触发器的种类及执行顺序

DML触发器的种类

语句级前触发器

语句级后触发器

行级前触发器

行级后触发器

2.DML触发器的执行顺序

如果存在,则执行语句级前触发器。

对于受触发事件影响的每一个记录:

如果存在,则执行行级前触发器;

执行当前记录的DML操作(触发事件);

如果存在,则执行行级后触发器。

如果存在,则执行语句级后触发器。

 

3.创建DML触发器

语法

CREATE [OR REPLACE] TRIGGER trigger_name

BEFORE|AFTER triggering_event [OF column_name]

ON table_name]

[FOR EACH ROW]

[WHEN trigger_condition]

DECLARE

     /*Declarative section is here */

BEGIN

     /*Exccutable section si here*/

EXCEPTION

     /*Exception section is here*/

END [trigger_name];

 

4.语句级触发器

在默认情况下创建的DML触发器为语句级触发器,即触发事件发生后,触发器只执行一次。

 

例:

创建一个触发器,禁止在休息日改变雇员信息

CREATE OR REPLACE TRIGGER trg_emp_weekend

BEFORE INSERT OR UPDATE OR DELETE

ON emp

BEGIN

   IF TO_CHAR(SYSDATE, 'DY', 'nls_date_language=

                         american') IN('SAT', 'SUN')

  THEN

      raise_application_error(-20000, 'Can''t operate

                                               in weekend. ');

  END IF;

END trg_emp_weekend;

 

例:

为emp表创建一个触发器,当执行插入操作时,统计操作后员工人数;当执行更新工资操作时,统计更新后员工平均工资;当执行删除操作时,统计删除后各个部门的人数。

CREATE OR REPLACE TRIGGER trg_emp_dml

AFTER INSERT OR UPDATE OR DELETE ON emp

DECLARE

  v_count NUMBER;

  v_sal   NUMBER(6,2);

BEGIN

  IF INSERTING THEN

    SELECT count(*) INTO v_count FROM emp;

    DBMS_OUTPUT.PUT_LINE(v_count);

  ELSIF UPDATING THEN

    SELECT avg(sal) INTO v_sal FROM emp;

    DBMS_OUTPUT.PUT_LINE(v_sal);

  ELSE

    FOR v_dept IN (SELECT deptno,count(*) num FROM emp

                                                   GROUP BY deptno) LOOP

      DBMS_OUTPUT.PUT_LINE(v_dept.deptno||' '||v_dept.num);

    END LOOP;

  END IF;

END trg_emp_dml;

 

5.行级触发器

行级触发器是指执行DML操作时,每操作一个记录,触发器就执行一次,一个DML操作涉及多少个记录,触发器就执行多少次。(书本P211,例12-2.)

在行级触发器中可以使用WHEN条件,进一步控制触发器的执行。

在行级触发器中引入了:old和:new 两个标识符,来访问和操作当前被处理记录中的数据。

标识符

:old和:new作为triggering_table%ROWTYPE类型的两个变量

在不同触发事件中,:old和:new的意义不同

触发事件

:old

:new

INSERT

未定义,所有字段都为NULL

当语句完成时,被插入的记录

UPDATE

更新前原始记录

当语句完成时,更新后的记录

DELETE

记录被删除前的原始值

未定义,所有字段都为NULL

引用方式

      :old.field和:new.field (执行部分)

       old.field 和new.field   (WHEN条件中)

注意事项:

是伪记录,不能作为整个记录进行赋值或引用

不能传递给带triggering_table%ROWTYPE参数的过程和函数

如果触发器是建立在嵌套表上,:old和:new都执行嵌套表的行,:parent指向父表中的当前行。

例:

为emp表创建一个触发器,当插入新员工时显示新员工的员工号、员工名;当更新员工工资时,显示修改前后员工工资;当删除员工时,显示被删除的员工号、员工名。

CREATE OR REPLACE TRIGGER trg_emp_dml_row

BEFORE INSERT OR UPDATE OR DELETE ON emp

FOR EACH ROW

BEGIN

   IF INSERTING THEN

         DBMS_OUTPUT.PUT_LINE(:new.empno||' '||

                                                :new.ename);

   ELSIF UPDATING THEN

         DBMS_OUTPUT.PUT_LINE(:old.sal||' '||:new.sal);

   ELSE

         DBMS_OUTPUT.PUT_LINE(:old.empno||' '||

                                                :old.ename);

   END IF;

END trg_emp_dml_row;

 

在行级触发器中,可以使用WHEN子句进一步控制触发器的执行。

例:

修改员工工资时,保证修改后的工资高于修改前的工资。

CREATE OR REPLACE TRIGGER trg_emp_update_row

BEFORE UPDATE OF sal ON emp

FOR EACH ROW

WHEN(new.sal<=old.sal)

BEGIN

    RAISE_APPLICATION_ERROR(

                    -20001,'The salary is lower!');

END trg_emp_update_row;

 

三、INSTEAD OF触发器

特点

只能定义在视图上

Instead-of触发器只能是行级触发器

Instead-of 触发器由DML操作激发,而DML操作本身并不执行

作用

修改一个本来不可以修改的视图

修改视图中某嵌套表的列

如果视图中包含下列任何一项,则该视图不可修改

集合操作符(UNION,UNION ALL,MINUS,INTERSECT);

聚集函数(SUM,AVG等);

GROUP BY,CONNECT BY或START WITH子句;

DISTINCT操作符;

涉及多个表的连接操作。

创建INSTEAD OF触发器的基本语法

CREATE [OR REPLACE] TRIGGER trigger_name

INSTEAD OF triggering_event [OF column_name]

ON view_name

FOR EACH ROW

[WHEN trigger_condition]

DECLARE

      /*Declarative section is here */

BEGIN

      /*Exccutable section si here*/

EXCEPTION

      /*Exception section is here*/

END [trigger_name];

 

例:

创建一个包括员工及其所在部门信息的视图empdept,然后向视图中插入一条记录(2345,’TOM’,3000,’SALES’)。

 

CREATE OR REPLACE VIEW empdept

AS

SELECT empno,ename,sal,dname

FROM emp,dept WHERE emp.deptno=dept.deptno  

WITH CHECK OPTION;

 

INSERT INTO empdept

VALUES(2345, 'TOM',3000, 'SALES');

*

ERROR 位于第 1 行:

ORA-01733: 此处不允许虚拟列

CREATE OR REPLACE TRIGGER trig_view

INSTEAD OF INSERT ON empdept

FOR EACH ROW

DECLARE

    v_deptno dept.deptno%type;

BEGIN

    SELECT deptno INTO v_deptno

    FROM dept WHERE dname=:new.dname;

    INSERT INTO emp(empno,ename,sal,deptno)   

    VALUES(:new.empno,:new.ename,v_deptno,:new.sal);

END trig_view;

再向视图中插入一条记录(2345,’TOM’,3000,’SALES’)。

INSERT INTO empdept

VALUES(2345, 'TOM',3000, 'SALES');

已创建1行。

 

四、系统触发器

1.触发事件

DDL(模式)事件

CREATE,ALTER,DROP,RENAME,GRANT,REVOKE,COMMENT,TRUNCATE等。

触发时间可以是BEFORE,也可以是AFTER。

数据库事件

STARTUP,SHUTDOWN,SERVERERROR,LOGON,LOGOFF等。

 

2.创建系统触发器

语法

CREATE [OR REPLACE] TRIGGER trigger_name

BEFORE|AFTER ddl_event_list|database_event_list

ON DATABASE|SCHEMA

[WHEN trigger_condition]

DECLARE

     /*Declarative section is here */

BEGIN

    /*Executable section is here*/

EXCEPTION

    /*Exception section is here*/

END [trigger_name];

说明

基于数据库(DATABASE)的触发器,只要系统中该触发事件发生,且满足触发条件,则触发器执行;

对于基于模式(SCHEMAN)的触发器,只有当特定模式中的触发事件发生时,触发器才执行。

注意

STARTUP和SHUTDOWN事件只能激发基于数据库的触发器。

 

例:

将每个用户的登录信息写入temp_table表中。

CREATE OR REPLACE TRIGGER log_user_connection

AFTER LOGON ON DATABASE

BEGIN

  INSERT INTO scott.temp_table

  VALUES (user,sysdate);

END log_user_connection;

 

例:

当数据库中执行CREATE操作时,将创建的对象信息记录到ddl_creations表中。

CREATE TABLE ddl_creations (

     user_id       VARCHAR2(30),

     object_type    VARCHAR2(20),

     object_name   VARCHAR2(30),

     object_owner  VARCHAR2(30),

     creation_date  DATE);

 

CREATE OR REPLACE TRIGGER log_creations

AFTER CREATE ON DATABASE

BEGIN

    INSERT INTO ddl_creations

    VALUES(ora_login_user, ora_dict_obj_type,

         ora_dict_obj_name, ora_dict_obj_owner, sysdate);

END log_creations;

 

五、变异表触发器

概念

变异表是指激发触发器的DML语句所操作的表,即触发器为之定义的表,或者由于DELETE CASCADE操作而需要修改的表,即当前表的子表。

约束表是指由于引用完整性约束而需要从中读取或修改数据的表,即当前表的父表。

 

六、触发器的管理

触发器名称

触发器存在于单独的名字空间中,在一个模式中可以与其他对象同名

 

触发器的限制

不能出现任何事务控制语句。因为触发器作为触发语句执行的一部分,处于同一个事务中。

一个事件最多创建12个触发器。

触发器的大小不能超过32K。

 

激活或禁用触发器

可以激活或禁用某个触发器。语法为

ALTER TRIGGER triggername ENABLE|DISABLE;

 

激活或禁用某个表对象上的所有触发器。语法为

ALTER TABLE table_name ENABLE|DISABLE ALL  TRIGGERS;

 

修改触发器

CREATE OR REPLACE TRIGGER trigger_name

 

重新编译触发器

ALTER TRIGGER trigger_name COMPILE;

 

查看触发器及其源代码

查询数据字典视图USER_TRIGGERS

SELECT trigger_name,trigger_type,

table_name,trigger_body FROM user_triggers;

 

删除触发器

当触发器不再需要时,可以使用DROP TRIGGER语句删除触发器。

DROP TRIGGER trigger_name;

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!