触发器
用来监视数据库的操作。
基本原理
相关概念
ORACLE 提供三个参数INSERTING, UPDATING,DELETING 用于判断触发了哪些操作。
谓词 行为
INSERTING 如果触发语句是 INSERT 语句,则为TRUE,否则为FALSE
UPDATING 如果触发语句是 UPDATE语句,则为TRUE,否则为FALSE
DELETING 如果触发语句是 DELETE 语句,则为TRUE,否则为FALSE
创建触发器
CREATE OR REPLACE TRIGGER tr_del_emp 定义一个触发器tr_del_emp
BEFORE DELETE --指定触发时机为删除操作前触发
ON scott.emp
FOR EACH ROW --说明创建的是行级触发器
when(new.Tname='David') --这一部分是触发条件
declare --触发体
begin
exception
end;
执行触发器
CREATE OR REPLACE TRIGGER tr_dept_time
BEFORE INSERT OR DELETE OR UPDATE --这一步体现了将所有的触发器都放在tr_dept_time中
ON departments
BEGIN
IF(TO_CHAR(sysdate,'DAY') IN ('星期六', '星期日')) OR (TO_CHAR(sysdate, 'HH24:MI') NOT BETWEEN '08:30' AND '18:00')THEN
RAISE_APPLICATION_ERROR(-20001, '不是上班时间,不能修改departments表');
ENDIF;
END;
删除触发器
编写触发器时,需要注意以下几点:
1、触发器不接受参数。
2、一个表上最多可有12个触发器,但同一时间、同一事件、同一类型的触发器只能有一个。并各触发器之间不能有矛盾。
这12种类型分别是:
BEFORE INSERT
BEFORE INSERT FOR EACH ROW
AFTER INSERT
AFTER INSERT FOR EACH ROW
BEFORE UPDATE
BEFORE UPDATE FOR EACH ROW
AFTER UPDATE
AFTER UPDATE FOR EACH ROW
BEFORE DELETE
BEFORE DELETE FOR EACH ROW
AFTER DELETE
AFTER DELETE FOR EACH ROW
3、在一个表上的触发器越多,对在该表上的DML操作的性能影响就越大。
4、触发器最大为32KB。若确实需要,可以先建立过程,然后在触发器中用CALL语句进行调用。
5、在触发器的执行部分只能用DML语句(SELECT、INSERT、UPDATE、DELETE),不能使用DDL语句(CREATE、ALTER、DROP)。
6、触发器中不能包含事务控制语句(COMMIT,ROLLBACK,SAVEPOINT)。因为触发器是触发语句的一部分,触发语句被提交、回退时,触发器也被提交、回退了。
7、在触发器主体中调用的任何过程、函数,都不能使用事务控制语句。
8、在触发器主体中不能申明任何Long和blob变量。新值new和旧值old也不能是表中的任何long和blob列。
9、不同类型的触发器(如DML触发器、INSTEADOF触发器、系统触发器)的语法格式和作用有较大区别。
创建替代(INSTEAD OF)触发器
基本语法
CREATE [OR REPLACE] TRIGGER trigger_name
INSTEAD OF
{INSERT | DELETE | UPDATE [OF column [, column …]]}
[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
ON [schema.] view_name --只能定义在视图上
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
[FOR EACH ROW ] --因为INSTEAD OF触发器只能在行级上触发,所以没有必要指定
[WHEN condition]
PL/SQL_block | CALL procedure_name;
INSTEAD OF 选项使ORACLE激活触发器,而不执行触发事件。只能对视图和对象视图建立INSTEAD OF触发器,而不能对表、模式和数据库建立INSTEAD OF 触发器。
REFERENCING 子句说明相关名称,在行触发器的PL/SQL块和WHEN 子句中可以使用相关名称参照当前的新、旧列值,默认的相关名称分别为OLD和NEW。触发器的PL/SQL块中应用相关名称时,必须在它们之前加冒号(:),但在WHEN子句中则不能加冒号。
WHEN 子句说明触发约束条件。Condition 为一个逻辑表达时,其中必须包含相关名称,而不能包含查询语句,也不能调用PL/SQL 函数。WHEN 子句指定的触发约束条件只能用在BEFORE 和AFTER 行触发器中,不能用在INSTEAD OF 行触发器和其它类型的触发器中。
创建INSTEAD OF触发器需要注意以下几点:
只能被创建在视图上,并且该视图没有指定WITH CHECK OPTION选项。
不能指定BEFORE 或 AFTER选项。
FOR EACH ROW子可是可选的,即INSTEAD OF触发器只能在行级上触发、或只能是行级触发器,没有必要指定。
没有必要在针对一个表的视图上创建INSTEAD OF触发器,只要创建DML触发器就可以了。
举个例子:SELECT deptno, count ( * ) total_employeer, sum (sal) total_salary
FROM emp GROUP BY deptno;
DELETE FROM emp_view WHERE deptno=10
ERROR 位于第 1 行:
ORA-01732: 此视图的数据操纵操作非法
但是我们可以创建INSTEAD_OF触发器来为 DELETE 操作执行所需的处理,即删除EMP表中所有基准行:INSTEAD OF DELETE ON emp_view
BEGIN
DELETE FROM emp WHERE deptno= :old.deptno;
END emp_view_delete;
DELETE FROM emp_view WHERE deptno=10;
DROP TRIGGER emp_view_delete;
DROP VIEW emp_view;