oracle学习笔记(二十九):触发器


1、触发器是一个与表相关联的、存储的 PLSQL 程序,每当一个特定的 数据操作语言(insert、delete、update)在指定的表上发出时,oracle 自动的执行触发器中定义的 语句序列。

 

2、触发器的类型:

语句级触发器:

        在指定的操作语句操作之前,或之后执行一次,不管这条语句影响了多少行;

行级触发器(for each row):

        触发语句作用的每一条记录都被触发。在行级触发器中,使用 :old 和 :new 伪记录变量,识别值的状态;

 

3、触发器可用于:

数据确认(后);

安全性检查(前);

 

4、触发器语法:

CREATE  [or REPLACE] TRIGGER  触发器名

{BEFORE | AFTER} ---- 之前触发 | 之后触发

{ INSERT | DELETE | UPDATE -----语句级触发

UPDATE OF 列名 }----行级

ON  表名

[FOR EACH ROW] ---- 行级触发

PLSQL 【declare…begin…end;/】


5、创建语句级触发器 insertEmpTrigger,当对表【emp】进行增加【insert】操作前【before】,显示 "hello world":

SQL> create or replace trigger insertEmpTrigger
  2  before
  3  insert
  4  on emp
  5  begin
  6      dbms_output.put_line('hello world');
  7  end;
  8  /

触发器已创建

6、查看已经创建好的触发器:

SQL> col TRIGGER_NAME for a16;
SQL> col TRIGGER_TYPE for a16;
SQL> col TRIGGERING_EVENT for a8;
SQL> col TABLE_NAME for a5;
SQL> col DESCRIPTION for a12;

SQL> select TRIGGER_NAME,TRIGGER_TYPE,TRIGGERING_EVENT,TABLE_NAME,DESCRIPTION from user_triggers;

TRIGGER_NAME     TRIGGER_TYPE     TRIGGERI TABLE DESCRIPTION
---------------- ---------------- -------- ----- ------------
INSERTEMPTRIGGER BEFORE STATEMENT INSERT   EMP   insertEmpTri
                                                 gger
                                                 before
                                                 insert
                                                 on emp

7、删除触发器:

SQL> drop trigger insertEmpTrigger;

触发器已删除。

8、使用 insert 语句插入一条记录,引起 insertEmpTrigger 触发器工作:

SQL> insert into emp(empno, ename, sal) values(1111, 'Jack', 2000);
hello world

已创建 1 行。

9、使用 insert 语句插入 N 条记录,引起 insertEmpTrigger 触发器工作:

SQL> insert into emp select * from xxx_emp;
hello world

已创建14行。

注意:从 89 可以看出来,不管插入多少条数据,触发器只会执行一次;这种叫做 语句级触发器;

10、创建语句级触发器 deleteEmpTrigger,当对表【emp】进行删除【delete】操作后【after】,显示 "world 触发器":

SQL> create or replace trigger deleteEmpTrigger
  2  after
  3  delete
  4  on emp
  5  begin
  6      dbms_output.put_line('hello 触发器');
  7  end;
  8  /

触发器已创建

11、使用 delete 语句删除一条记录,引起 deleteEmpTrigger 触发器工作:

SQL> delete from emp where empno = 1111;
hello 触发器

已删除 1 行。

12、星期一到星期五,且 7-23 点能向数据库 emp 表插入数据,否则使用函数抛出异常:

语法:raise_application_error('-20000', '例外原因')

SQL> create or replace trigger securityTrigger
  2  before insert on emp
  3  declare
  4      pday varchar2(10);
  5      phour number(2);
  6  begin
  7      -- 获取星期
  8      select to_char(sysdate, 'day') into pday from dual;
  9
 10      -- 获取时间
 11      select to_char(sysdate, 'hh24') into phour from dual;
 12
 13      -- 业务
 14      if ((pday in ('星期六', '星期日')) or (phour not between 7 and 23)) then
 15          -- 抛异常
 16          raise_application_error('-20000', '非工作时间,不能向 emp 表中插入数据');
 17      end if;
 18  end;
 19  /

触发器已创建

测试异常情况:

SQL> insert into emp(empno, ename, sal) values(1111, 'Jack', 2000);
insert into emp(empno, ename, sal) values(1111, 'Jack', 2000)
            *
第 1 行出现错误:
ORA-20000: 非工作时间,不能向 emp 表中插入数据
ORA-06512: 在 "SCOTT.SECURITYTRIGGER", line 14
ORA-04088: 触发器 'SCOTT.SECURITYTRIGGER' 执行过程中出错

13、创建行级触发器 checkSalaryTrigger,涨后工资这一列,确保大于涨前工资,语法:for each row/:new.sal/:old.sal

SQL> create or replace trigger checkSalaryTrigger
  2  after
  3  update of sal --在更新 sal 之后触发
  4  on emp
  5  for each row
  6  begin
  7      -- 如果 涨后工资 > 涨前工资
  8      if :old.sal > :new.sal then
  9          -- 抛异常
 10          raise_application_error('-20000', '工资不能越涨越低');
 11          dbms_output.put_line('涨工资失败');
 12      else
 13          dbms_output.put_line('涨工资成功');
 14      end if;
 15  end;
 16  /

触发器已创建

测试异常情况:

SQL> update emp set sal = sal - 100 where empno = 7369;
update emp set sal = sal - 100 where empno = 7369
       *
第 1 行出现错误:
ORA-20000: 工资不能越涨越低
ORA-06512: 在 "SCOTT.CHECKSALARYTRIGGER", line 5
ORA-04088: 触发器 'SCOTT.CHECKSALARYTRIGGER' 执行过程中出错

测试正常情况:

SQL> update emp set sal = sal + 100 where empno = 7369;
涨工资成功

已更新 1 行。

测试更新 多条数据的情况:可以看出,行级触发器每更新一条记录就会触发一次;

SQL> update emp set sal = sal + 100 where deptno = 10;
涨工资成功
涨工资成功
涨工资成功

已更新3行。

测试更新 别的字段的情况:可以看出,更新别的字段,触发器不会触发;只有更新 sal 字段,才会触发;

SQL> update emp set comm = comm + 100 where deptno = 10;

已更新3行。

 

 

oracle触发器实例讲解2008-11-27 09:17--[6]// Oracle Trigger ---------------------------------------------------------------------------------------------// --实例1------------------------ --创建触发器,当用户对test表执行DML语句时,将相关信息记录到日志表 --创建测试表 CREATE TABLE test ( t_id NUMBER(4), t_name VARCHAR2(20), t_age NUMBER(2), t_sex CHAR ); --创建记录测试表 CREATE TABLE test_log ( l_user VARCHAR2(15), l_type VARCHAR2(15), l_date VARCHAR2(30) ); --创建触发器 CREATE OR REPLACE TRIGGER test_trigger AFTER DELETE OR INSERT OR UPDATE ON test DECLARE v_type test_log.l_type%TYPE; BEGIN IF INSERTING THEN --INSERT触发 v_type := 'INSERT'; DBMS_OUTPUT.PUT_LINE('记录已经成功插入,并已记录到日志'); ELSIF UPDATING THEN --UPDATE触发 v_type := 'UPDATE'; DBMS_OUTPUT.PUT_LINE('记录已经成功更新,并已记录到日志'); ELSIF DELETING THEN v_type := 'DELETE'; DBMS_OUTPUT.PUT_LINE('记录已经成功删除,并已记录到日志'); END IF; INSERT INTO test_log VALUES(user,v_type, TO_CHAR(sysdate,'yyyy-mm-dd hh24:mi:ss')); END; / --下面我们来分别执行DML语句 INSERT INTO test VALUES(101,'zhao',22,'M'); UPDATE test SET t_age = 30 WHERE t_id = 101; DELETE test WHERE t_id = 101; --然后查看效果 SELECT * FROM test; SELECT * FROM test_log; --实例2------------------------ --创建触发器,它将映射emp表中每个部门的总人数和总工资 --创建映射表 CREATE TABLE dept_sal AS SELECT deptno,COUNT(empno) AS total_emp,SUM(sal) AS total_sal FROM emp GROUP BY deptno; DESC dept_sal; --创建触发器 CREATE OR REPLACE TRIGGER emp_info AFTER INSERT OR UPDATE OR DELETE ON emp DECLARE CURSOR cur_emp IS SELECT deptno,COUNT(empno) AS total_emp,SUM(sal) AS total_sal FROM emp GROUP BY deptno; BEGIN DELETE dept_sal; --触发时首先删除映射表信息 FOR v_emp IN cur_emp LOOP --DBMS_OUTPUT.PUT_LINE(v_emp.deptno || v_emp.total_emp || v_emp.total_sal); --插入数据 INSERT INTO dept_sal VALUES(v_emp.deptno,v_emp.total_emp,v_emp.total_sal); END LOOP; END; / --对emp表进行DML操作 INSERT INTO emp(empno,deptno,sal) VALUES('123','10',10000); SELECT * FROM dept_sal; DELETE EMP WHERE empno=123; SELECT * FROM dept_sal; --实例3------------------------ --创建触发器,它记录表的删除数据 --创建表 CREATE TABLE employee ( id VARCHAR2(4) NOT NULL, name VARCHAR2(15) NOT NULL, age NUMBER(2) NOT NULL, sex CHAR NOT NULL ); DESC employee; --插入数据 INSERT INTO employee VALUES('e101','zhao',23,'M'); INSERT INTO employee VALUES('e102','jian',21,'F'); --创建记录表 CREATE TABLE old_employee AS SELECT * FROM employee; DESC old_employee; --创建触发器 CREATE OR REPLACE TRIGGER tig_old_emp AFTER DELETE ON employee -- FOR EACH ROW --语句级触发,即每一行触发一次 BEGIN INSERT INTO old_employee VALUES(:old.id,:old.name,:old.age,:old.sex); --:old代表旧值 END; / --下面进行测试 DELETE employee; SELECT * FROM old_employee; --实例4------------------------ --创建触发器,利用视图插入数据 --创建表 CREATE TABLE tab1 (tid NUMBER(4) PRIMARY KEY,tname VARCHAR2(20),tage NUMBER(2)); CREATE TABLE tab2 (tid NUMBER(4),ttel VARCHAR2(15),tadr VARCHAR2(30)); --插入数据 INSERT INTO tab1 VALUES(101,'zhao',22); INSERT INTO tab1 VALUES(102,'yang',20); INSERT INTO tab2 VALUES(101,'13761512841','AnHuiSuZhou'); INSERT INTO tab2 VALUES(102,'13563258514','AnHuiSuZhou'); --创建视图连接两张表 CREATE VIEW tab_view AS SELECT tab1.tid,tname,ttel,tadr FROM tab1,tab2 WHERE tab1.tid = tab2.tid; --创建触发器 CREATE OR REPLACE TRIGGER tab_trigger INSTEAD OF INSERT ON tab_view BEGIN INSERT INTO tab1(tid,tname) VALUES(:new.tid,:new.tname); INSERT INTO tab2(ttel,tadr) VALUES(:new.ttel,:new.tadr); END; / --现在就可以利用视图插入数据 INSERT INTO tab_view VALUES(105,'zhaoyang','13886681288','beijing'); --查看效果 SELECT * FROM tab_view; --实例5------------------------ --创建触发器,比较emp表中更新的工资 CREATE OR REPLACE TRIGGER sal_emp BEFORE UPDATE ON emp FOR EACH ROW BEGIN IF :OLD.sal > :NEW.sal THEN DBMS_OUTPUT.PUT_LINE('工资减少'); ELSIF :OLD.sal < :NEW.sal THEN DBMS_OUTPUT.PUT_LINE('工资增加'); ELSE DBMS_OUTPUT.PUT_LINE('工资未作任何变动'); END IF; DBMS_OUTPUT.PUT_LINE('更新前工资 :' || :OLD.sal); DBMS_OUTPUT.PUT_LINE('更新后工资 :' || :NEW.sal); END; / --执行UPDATE查看效果 UPDATE emp SET sal = 3000 WHERE empno = '7788'; --实例6------------------------ --创建触发器,将操作CREATE、DROP存储在log_info表 --创建表 CREATE TABLE log_info ( manager_user VARCHAR2(15), manager_date VARCHAR2(15), manager_type VARCHAR2(15), obj_name VARCHAR2(15), obj_type VARCHAR2(15) ); --创建触发器 CREATE OR REPLACE TRIGGER trig_log_info AFTER CREATE OR DROP ON SCHEMA BEGIN INSERT INTO log_info VALUES(USER,SYSDATE,SYS.DICTIONARY_OBJ_NAME,SYS.DICTIONARY_OBJ_OWNER, SYS.DICTIONARY_OBJ_TYPE); END; / --测试语句 CREATE TABLE a(id NUMBER); CREATE TYPE aa AS OBJECT(id NUMBER); / DROP TABLE a; DROP TYPE aa; --查看效果 SELECT * FROM log_info; --相关数据字典-----------------------------------------------------// SELECT * FROM USER_TRIGGERS; SELECT * FROM ALL_TRIGGERS; SELECT * FROM DBA_TRIGGERS; --必须以DBA身份登陆才能使用此数据字典 --启用和禁用 ALTER TRIGGER trigger_name DISABLE; ALTER TRIGGER trigger_name ENABLE;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值