CREATE TRIGGER

说明

定义一个新的触发器,触发器分为普通 DML 触发器、约束触发器、INSTEAD OF DML 触发器、系统触发器。

在下列情况之一发生时,数据库会自动激活触发器:

  1. 与表、模式或者数据库相关联的PLOSCAR块被执行。
  2. 匿名的PLOSCAR块或者通过PLOSCAR块、Java来实现调用的过程被执行。

语法

create_trigger ::=

create_simple_dml_trigger ::=

create_constraint_trigger ::=

create_instead_of_dml_trigger ::=

create_system_trigger ::=

dml_trig_events ::=

sys_trig_events ::=

opt_TriggerWhen ::=

exe_procedure_statement ::=

pl_block ::=

参数

BEFORE

事件前触发

AFTER

事件后触发

TriggerEvents

触发器的触发事件

sys_trig_events

激活系统触发器的事件

pl_block

触发器的触发的执行块

declarations

PL块的声明语句,请参照 PL过程语言开发手册

statements

PL块的执行语句,请参照 PL过程语言开发手册

table

触发器作用的表名

view

触发器作用的视图名

constr_table

约束所在表名

FOR [ EACH ] { ROW | STATEMENT }

  • ROW行级触发器
  • STATEMENT语句级触发器

默认为STATEMENT语句级触发器

proc

用户提供的存储过程。

arguments

一个可选的用逗号分隔的参数列表,它将在触发器执行的时候提供给函数。 这些参数是文本字符串常量。也可以在这里写简单的名字和数值常量, 但是它们会被转换成字符串。请检查实现语言中关于如何在触发器函数中访问触发器参数的描述; 这些参数可能和普通的函数参数不同。对于PLOSCAR语言函数, 可以通过TG_NARGS获得触发器参数个数,通过TG_ARGV[]数组获得触发器参数。 参考 PL过程语言开发手册 存储过程的使用/作为触发器函数。

WHEN ( condition_expr )

指定触发条件,用于数据库针对某行数据判断是否需要触发Trigger。 若对于某行数据来说,条件判断为真,则针对这行数据执行触发器Body部分;否则不执行。 在行级触发器和语句级触发器中均可指定触发条件,只是在语句级触发器的触发条件中,不能出现列名。

注解

  • 触发器可以声明为在对记录进行操作之前(在检查约束之前和 INSERT,UPDATE 或 DELETE 执行前)或之后(在检查约束之后和完成 INSERT, UPDATE 或 DELETE 操作)触发。
  • 如果触发器在事件之前,触发器可能略过对当前记录的操作或改变被插入的记录(只对 INSERT 和 UPDATE 操作有效)。
  • 如果触发器在事件之后,包括最后的插入、更新或删除的所有更改对触发器都是"可见"的。
  • 如果多个同类型的触发器为同样事件做了定义,那么它们将按照字母顺序被激活。
  • 行级触发器通过 UPDATE OF column 的形式可以作用到各个列(字段),这就是列级触发器。 实际上,列级触发器就是带有待更新列链表的行级触发器。 只有在这个链表中的某一列被更新时,才会触发列级触发器。 不带有这种链表的触发器,表中任何一列被更新,都会触发该触发器。
  • 值得注意的是,列级触发器的待更新列被删除或者重命名时,它对应的触发器就失效了。 删除或者重命名该列时,并不马上提示触发器失效。 只有在这个触发器即将被触发器时,具体一点就是有记录被更新(不包括删除记录和添加记录操作)时, 它才会重新验证该触发器的定义,从而再作出失效的提示。 如果之后再添加与被删除列同名的列,那么之前失效的列级触发器就会重新变得有效。
  • SELECT 并不更改任何行,因此不能创建 SELECT 触发器。这种场合下视图更合适些。
  • 在创建触发器时,还需满足一下前提条件:
    1. 不论是在当前模式下还是其他模式下将触发器创建到当前模式还是其他模式,亦或是将触发器创建到其他用户的模式下, 创建触发器的用户都必须具有相应的 CREATE TRIGGER 的系统权限。
    2. 当对DATABASE创建触发器时,除了具有上述权限外,用户还必须具有 ADMINISTER DATABASE TRIGGER 的系统权限。
    3. 当创建一个 crossedition trigger 的时候,除了要求具有上述权限外,用户还必须被允许 ENABLE EDITIONS。
    4. 触发器的所有者必须具有对触发器的执行权限以执行触发器,这些权限必须被直接赋予而不能通过角色赋予。
  • 关于 instead of dml 触发器的几点说明:
    1. instead of dml trigger使用触发器内部动作替代dml操作, 比如一个instead of update触发器的内部动作会替代一次update操作,即不更新数据。
    2. instead of dml 触发器只能指定为行级,不能指定为语句级。
    3. instead of update 触发器不能指定为由列级更新触发。

示例

示例1: 创建普通 DML 触发器、约束触发器

--  清理环境
DROP TRIGGER trg1;
DROP TABLE tab1 CASCADE;


--  创建表
CREATE TABLE tab1 (a INT);


--  创建触发器
CREATE OR REPLACE TRIGGER trg1 BEFORE INSERT ON tab1 FOR EACH ROW
BEGIN
    RAISE NOTICE 'trg1!';
END;
/


--  触发 TRIGGER    
INSERT INTO tab1 VALUES(1);
1
NOTICE, trg1!
INSERT INTO tab1 VALUES(2);
1
NOTICE, trg1!
INSERT INTO tab1 VALUES(3);
1
NOTICE, trg1!


SELECT * FROM tab1 ORDER BY a;
A(int)      |
------------
1           |
------------
2           |
------------
3           |
总数目:3


--  删除触发器和表
DROP TRIGGER trg1;
DROP TABLE tab1;

示例2: 创建触发器(使用触发器函数)

--  清理环境
DROP TRIGGER trg2;
DROP PROCEDURE proc2;
DROP TABLE tab2 CASCADE;


--  创建表
CREATE TABLE tab2 (a INT);


--  创建触发器函数
CREATE OR REPLACE PROCEDURE proc2() AS
BEGIN
    RAISE NOTICE 'proc2!';
END;
/


--  创建触发器
CREATE OR REPLACE TRIGGER trg2 BEFORE INSERT OR UPDATE ON tab2 FOR EACH ROW
EXECUTE PROCEDURE proc2();/


--  触发 TRIGGER    
INSERT INTO tab2 VALUES(1);
1
NOTICE, proc2!
INSERT INTO tab2 VALUES(2);
1
NOTICE, proc2!
UPDATE tab2 SET a = 5;
2
NOTICE, proc2!
NOTICE, proc2!


SELECT * FROM tab2 ORDER BY a;
A(int)      |
------------
5           |
------------
5           |
总数目:2


--  删除触发器、触发器函数和表
DROP TRIGGER trg2;
DROP PROCEDURE proc2;
DROP TABLE tab2;

示例3: 创建 INSTEAD OF DML 触发器

--  清理环境
DROP TRIGGER trg3;
DROP VIEW view3 CASCADE;
DROP TABLE tab4 CASCADE;
DROP TABLE tab3 CASCADE;


--  创建表并插入数据
CREATE TABLE tab3 (t3a INT);

INSERT INTO tab3 VALUES(100);


SELECT * FROM tab3 ORDER BY t3a;
T3A(int)      |
--------------
100           |
总数目:1


CREATE TABLE tab4 (t4a INT, t4b INT);

INSERT INTO tab4 VALUES(2000, 30000);


SELECT * FROM tab4 ORDER BY t4a, t4b;
T4A(int)      |T4B(int)      |
----------------------------
2000          |30000         |
总数目:1


--  创建视图
CREATE VIEW view3 AS SELECT t3a AS v3a, t4b AS v3b FROM tab3, tab4;


SELECT * FROM view3 ORDER BY v3a, v3b;
V3A(int)      |V3B(int)      |
----------------------------
100           |30000         |
总数目:1


--  创建 INSTEAD OF DML 触发器
CREATE TRIGGER trg3 INSTEAD OF UPDATE ON view3 FOR EACH ROW    
BEGIN
    UPDATE tab3 SET t3a = :NEW.v3a + 1;
    UPDATE tab4 SET t4b = :NEW.v3b + 2;
END;    
/
    

--  触发 TRIGGER,执行触发器内匿名块动作
update view3 SET v3a = 300, v3b = 5000;


SELECT * FROM tab3 ORDER BY t3a;
T3A(int)      |
--------------
301           |
总数目:1


SELECT * FROM tab4 ORDER BY t4a, t4b;
T4A(int)      |T4B(int)      |
----------------------------
2000          |5002          |
总数目:1


SELECT * FROM view3 ORDER BY v3a, v3b;
V3A(int)      |V3B(int)      |
----------------------------
301           |5002          |
总数目:1



--  删除触发器、视图和表
DROP TRIGGER trg3;
DROP VIEW view3;
DROP TABLE tab4;
DROP TABLE tab3;

示例4: 创建列级触发器

--  清理环境
DROP TRIGGER trg4;
DROP TABLE tab4 CASCADE;


--  创建表并插入数据
CREATE TABLE tab4 (a INT, b INT);

INSERT INTO tab4 VALUES(1, 11);
INSERT INTO tab4 VALUES(2, 12);
INSERT INTO tab4 VALUES(3, 13);


SELECT * FROM tab4 ORDER BY a;
A(int)      |B(int)      |
------------------------
1           |11          |
------------------------
2           |12          |
------------------------
3           |13          |
总数目:3


--  创建列级触发器
CREATE OR REPLACE TRIGGER trg4 BEFORE UPDATE OF a ON tab4 FOR EACH ROW
BEGIN
    RAISE NOTICE 'trg4!';
END;
/


--  更新列不是触发器所在列
--  未触发 TRIGGER
UPDATE tab4 SET b = 22;


SELECT * FROM tab4 ORDER BY a;
A(int)      |B(int)      |
------------------------
1           |22          |
------------------------
2           |22          |
------------------------
3           |22          |
总数目:3

--  更新列不是触发器所在列,触发 TRIGGER    
UPDATE tab4 SET a = 1;
3
NOTICE, trg4!
NOTICE, trg4!
NOTICE, trg4!


SELECT * FROM tab4 ORDER BY a;
A(int)      |B(int)      |
------------------------
1           |22          |
------------------------
1           |22          |
------------------------
1           |22          |
总数目:3


--  删除触发器和表
DROP trigger trg4;
DROP TABLE tab4;

示例5: 使用触发器参数

--  清理环境
DROP TRIGGER trg5;
DROP PROCEDURE proc5;
DROP TABLE tab5 CASCADE;


--  创建表
CREATE TABLE tab5 (a INT);

--  创建触发器函数
CREATE PROCEDURE proc5(a VARCHAR2(10), b VARCHAR2(10), c INT) AS
BEGIN    
    DBMS_OUTPUT.PUT_LINE('ARG[0]:' || a);    
    DBMS_OUTPUT.PUT_LINE('ARG[1]:' || b);    
    DBMS_OUTPUT.PUT_LINE('ARG[2]:' || c);
END;
/

--  创建触发器(带有三个参数)
CREATE TRIGGER trg5 BEFORE INSERT ON tab5
FOR EACH ROW EXECUTE PROCEDURE proc5('abc', '123', 2046);/


--  触发 TRIGGER    
INSERT INTO tab5 VALUES(1);
1
ARG[0]:abc
ARG[1]:123
ARG[2]:2046


SELECT * FROM tab5 ORDER BY a;
A(int)      |
------------
1           |
总数目:1


--  删除触发器、触发器函数和表
DROP trigger trg5;
DROP PROCEDURE proc5;
DROP TABLE tab5;