触发器(TRIGGER)是一类特殊的存储过程,它可以对表进行插入、修改、删除时被激发激活而执行的数据库对象
触发器可以分为前触发器、后触发器、行触发器
所谓行触发器是指被定义的行数据发生变化时,二执行的数据库对象,被称为行触发器
创建触发器:
CREATE [OR REPLACE] TRIGGER trigger_name BEFORE|AFTER INSERT|UPDATE|DELETE 在激活动作之前(后)创建触发器 ON table_name [FOR EACH ROW] [WHEN condition_expression] PL/SQL;
说明:
OR REPLACE:替换,但不是万能替换,只有这个触发器名已经存在,并且时同一个表的触发器才会替换;
BEFORE|AFTER:触发器的激活时机;
INSERT|UPDATE|DELETE:触发器的激活动作;
ON table_name:触发器的作用表;
FOR EACH ROW:创建行触发器;
WHEN condition_expression:行触发器的激活条件,但要注意,行触发器可以没有激活条件,但是有激活条件必有行触发器;
PL/SQL:触发器的主体部分;
在触发器中如果需要定义变量需要有 DECLARE 关键字,因为存储过程不需要
【例】创建temp(ID,NAME),向temp中添加记录前,将temp表中所有记录删除
CREATE TABLE temp ( ID NUMBER(3), NAME VARCHAR2(10) ) INSERT INTO temp VALUES(1,'a'); INSERT INTO temp VALUES(2,'b'); INSERT INTO temp VALUES(4,'d'); CREATE TRIGGER tr1 BEFORE INSERT ON temp BEGIN DELETE FROM temp; END;
删除触发器:
语法:
DROP TRIGGER trigger_name;
触发器实现原理:
oracle 中有两个特殊变量:NEW 和 OLD 他们的数据类型时%ROWTYPE:
NEW INSERT /UPDATE
OLD DELETE /UPDATE
在触发器说明部分可以直接使用 NEW 或 OLD 变量,但在主体部分中使用这两个变量一定要加“:”,也就是:':new'和':old'
解说:当激活动作时 INSERT 或 UPDATE 时, NEW 变量中始终存放新添加或修改后的那条记录;当激活动作是 UPDATE 或 DELETE 时,OLD 变量中始终存放删除后或修改前的那条记录,这就是触发器的实现原理
例:创建score表,字段有id和grade(成绩),当向这个表中添加记录后,要求显示新添加学生的编号
CREATE TABLE score ( ID NUMBER(3), grade NUMBER(4,1) ) CREATE TRIGGER tr1 AFTER INSERT ON score FOR EACH ROW BEGIN dbms_output.put_line('新添加的学生编号是:':new.id); END; INSERT INTO score VALUES(10,87);
例:当销售一种商品时,要求这种商品的库存量做出相应的减少
CREATE TRIGGER tr1 AFTER INSERT ON shop_xs FOR EACH ROW BEGIN UPDATE shop_jb SET stock=stock-:new.quantity WHERE ID=:new.id; dbms_output.put_line(:new.id||'号商品的库存量被修改'); END; INSERT INTO shop_xs VALUES(10,1000,9,SYSDATE,009);
例:
创建score表,包含两个字段,分别为id和grade,向表中添加5条记录
创建触发器,实现当修改这个表中学生成绩字段后,如果该学生成绩及格要求显示:
那个学生的成绩被修改
修改前学生的成绩是多少
修改后学生的成绩是多少
该学生的成绩是提高了还是后退了
前进或后退了多少分
CREATE TRIGGER tr1 AFTER UPDATE ON score FOR EACH ROW WHEN(new.grade>=60) DECLARE v_gradiff INT :=:new.grade-:old.grade; BEGIN dbms_output.put_line(:new.id||'号学生成绩被修改'); dbms_output.put_line('修改前学生的成绩为:'||:old.grade||'分'); dbms_output.put_line('修改后学生的成绩为:'||:new.grade||'分'); IF v_gradiff>0 THEN dbms_output.put_line('该学生成绩提高了'||v_gradiff||'分'); ELSIF v_gradiff<0 THEN dbms_output.put_line('该学生后退了'||ABS(v_gradiff)||'分'); ELSE dbms_output.put_line('你很厉害啊,成绩保持得非常号...'); END IF; END;