目录
一、概述
Oracle的触发器(Trigger)与存储过程一样,都是嵌入到Oracle的一段程序。它是由事件触发某个操作,包括INSERT, UPDATE, DELETE语句。当数据库执行上述DML,就会激发触发器执行相应操作。触发程序是与表有关的命名数据库对象。
Trigger是特殊的存储过程,但不需要手动来调用(如:EXEC语句)。
二、创建单个执行语句的触发器
公式:
CREATE TRIGGER trigger_name trigger_time trigger_event
ON tb_name
FOR EACH ROW trigger_stmt
- trigger_time:触发器时机( BEFORE.../ AFTER... )
- trigger_event:标识触发事件( INSERT, UPDATE, DELETE )
- trigger_stmt:触发器程序体( BEGIN...END )
实例1:一个超简单的单执行语句
首先创建一个account表
CREATE TABLE tb_account
(
acct_num NUMBER(6), amount NUMBER(10,2)
);
SQL> desc tb_account;
Name Type Nullable Default Comments
-------- ------------ -------- ------- --------
ACCT_NUM NUMBER(6) Y
AMOUNT NUMBER(10,2) Y
创建触发器 INS_SUM
create or replace trigger INS_SUM
before insert
on tb_account
BEGIN
DBMS_OUTPUT.PUT_LINE('下面将开始插入数据');
END INS_SUM;
插入后结果为:
SQL> INSERT INTO tb_account values(1,8900.23);
下面将开始插入数据
1 row inserted
实例2:每当插入或更新表时自动给某字段赋值。
假设有一个员工表:
SQL> DESC employees
Name Type Nullable Default Comments
---------------- ------------ -------- ------- --------
EMPLOYEE_ID NUMBER(6) Y
FIRST_NAME VARCHAR2(20) Y
LAST_NAME VARCHAR2(25) Y
SALARY NUMBER(8,2) Y
LAST_UPDATE_TIME TIMESTAMP(6) Y
创建触发器 emp_last_update_time
CREATE OR REPLACE TRIGGER emp_last_update_time
BEFORE INSERT OR UPDATE
ON employees
REFERENCING NEW AS nnn -- 做了个引用,取别名
FOR EACH ROW
BEGIN
:nnn.last_update_time := current_timestamp;
END;
/
INSERT INTO employees VALUES (1, 'Scb', 'Leonardo', 8888, null);
SQL> SELECT * FROM EMPLOYEES;
EMPLOYEE_ID FIRST_NAME LAST_NAME SALARY LAST_UPDATE_TIME
----------- -------------------- ------------------------- ---------- --------------------------------------------------------------------------------
1 Scb Leonardo 8888.00 22-1月 -19 03.44.51.234000 下午
案例3:old值的使用
employees 表的 salary 值是非常重要的,
对它的任何修改我们都希望记录下来
创建相同表结构的employees_hist
CREATE table employees_hist
AS SELECT * FROM employees
WHERE 1=0;
创建触发器emp_salary
CREATE OR REPLACE TRIGGER emp_salary
BEFORE UPDATE OF salary
ON employees
REFERENCING old AS o
FOR EACH ROW
BEGIN
INSERT INTO employees_hist VALUES (:o.employee_id, :o.first_name,
:o.last_name, :o.salary, current_timestamp);
END;
/
UPDATE薪酬记录
UPDATE EMPLOYEES SET salary=6699.00 WHERE LAST_NAME='Leonardo';
SQL> SELECT * FROM employees;
EMPLOYEE_ID FIRST_NAME LAST_NAME SALARY LAST_UPDATE_TIME
----------- -------------------- ------------------------- ---------- --------------------------------------------------------------------------------
1 Scb Leonardo 6699.00 22-1月 -19 04.18.16.186000 下午
SQL> SELECT * FROM employees_hist;
EMPLOYEE_ID FIRST_NAME LAST_NAME SALARY LAST_UPDATE_TIME
----------- -------------------- ------------------------- ---------- --------------------------------------------------------------------------------
1 Scb Leonardo 8888.00 22-1月 -19 04.18.16.186000 下午
before 和after的区别:
- before:insert update 可以对new进行修改。
- after :不能对new 进行修改
- 二者都不能对old 进行修改
三、创建多个执行语句的触发器
实例:一个触发器,多个执行语句,操作多个表。
首先创建4张表
CREATE TABLE test1(a1 NUMBER(6));
CREATE TABLE test2(a2 NUMBER(6));
CREATE TABLE test3(a3 NUMBER(6) GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY);
CREATE TABLE test4(
a4 NUMBER(6) GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- Oracle12c版本以上适用
b4 NUMBER(6) DEFAULT 0
);
创建触发器:
CREATE TRIGGER TESTREF
BEFORE INSERT
ON test1
FOR EACH ROW
BEGIN
INSERT INTO test2 SET a2 = NEW.a1; -- Oracle12c写法
DELETE FROM test3 WHERE a3 = NEW.a1;
UPDATE test4 SET b4 = b4 + 1 WHERE a4 = NEW.a1;
END;
CREATE OR REPLACE TRIGGER TESTREF
BEFORE INSERT
ON test1
FOR EACH ROW
BEGIN
INSERT INTO test2 VALUES (:NEW.a1); --11g写法
DELETE FROM test3 WHERE a3 = :NEW.a1;
UPDATE test4 SET b4 = b4 + 1 WHERE a4 = :NEW.a1;
END;
向test1表中插入多条记录:
SQL> INSERT INTO test1 VALUES (1);
SQL> INSERT INTO test1 VALUES (3);
SQL> INSERT INTO test1 VALUES (1);
SQL> INSERT INTO test1 VALUES (7);
SQL> INSERT INTO test1 VALUES (7);
SQL> INSERT INTO test1 VALUES (8);
SQL> INSERT INTO test1 VALUES (4);
SQL> INSERT INTO test1 VALUES (4);
那么4个表中的数据如下:
SQL> SELECT * FROM test1;
A1
------
1
3
1
7
1
8
4
4
--------
SQL> SELECT * FROM test2;
A2
------
1
3
1
7
1
8
4
4
SQL> SELECT * FROM test3;
A3
----
2
5
6
9
10
SQL> SELECT * FROM test4;
A4 B4
---- ------
1 3
2 0
3 1
4 2
5 0
6 0
7 1
8 1
9 0
10 0
更多参考:https://blog.youkuaiyun.com/shangboerds/article/details/43030185
实例:INSTEAD OF触发器操作视图
对于简单视图,可以直接执行INSERT,UPDATE和DELETE操作
但是对于复杂视图,不允许直接执行INSERT,UPDATE和DELETE操作。
为了在具有以上情况的复杂视图上执行DML操作需要使用 INSTEAD OF触发器来完成。
创建视图 order_info
CREATE OR REPLACE VIEW order_info AS
SELECT c.customer_id, c.cust_last_name,
c.cust_first_name, o.order_id, o.order_date, o.order_status
FROM customers c, orders o
WHERE c.customer_id = o.customer_id;
用户信息&对应订单信息集合的视图 。
定义INSTEAD OF触发器
CREATE OR REPLACE TRIGGER order_info_insert
INSTEAD OF INSERT ON order_info
BEGIN
INSERT INTO customers (customer_id, cust_last_name, cust_first_name)
VALUES (:new.customer_id, :new.cust_last_name, :new.cust_first_name);
INSERT INTO orders (order_id, order_date, customer_id)
VALUES (:new.order_id, :new.order_date, :new.customer_id);
END order_info_insert;
若order_info视图被插入,就进行多个表的记录插入