Oracle触发器简单使用记录

在ORACLE系统里,触发器类似函数和过程。
1、触发器类型:(一般为:语句级触发器和行级触发器。)
1)、DML触发器: 创建在表上,由DML事件引发
2)、instead of触发器: 创建在视图上并且只能在行级上触发,用于替代insert,delete等操作(由于oracle中不能直接对有两个以上的表建立的视图进行DML操作,所以给出替代触发器,它是专门为进行视图操作的一种处理方法)
3)、DDL触发器: 触发事件时数据库对象的创建和修改
4)、数据库事件触发器:定义在数据库或者模式上,由数据库事件触发

语法:
create or replace trigger 触发器名
<before | after | instead of> <insert | update | delete>--<insert | update | delete>可以选择一个或多个DML语句,如果选择多个,则用or分开,如:insert or update。
on 表名或者视图名或者用户名或者数据库名
[for each row] [触发级别]针对一个表或视图创建trigger时分为statement级别与row级别的trigger.所谓statement级别是说一个sql语句触发一次trigger,而如果是row级别则一个sql语句涉及到多行数据则trigger会被触发多次
when(condition)[when判断条件]
[declare 变量] 11g
begin
pl/sql语句;
end 触发器名;
(注:代码涉及到对关联表的数据操作,在行级触发器中使用,将会报ORA-04091错误。这时可以通过自制事务来规避,弊端是使用自制事务后无法回滚rollback)
触发时间:before/after 在指定的事件发生之前/后执行触发器 instead of 触发器用在对视图的更新上。
触发事件:Insert,update,delete,create(创建对象时),alter,drop,logon/logoff(用户的登录或注销时执行触发器),startup/shutdown(数据库打开或关闭时执行触发器)。
常见的是DML(insert,update,delete) , DDL(create,alter,drop)语句
触发级别:for each row(行级触发)对触发事件影响的每一行执行触发器,即触发机制是基于行的。改一行数据,触发一次。
不写为语句触发(对触发事件只能触发一次,而且不能该问受触发器影响的每一行的值。既无论这条SQL语句影响多少条记录,触发器都只触发一次。)
WHEN后跟的condition:是触发器的响应条件,只对BEFORE和AFTER行级触发器有效,当操作的记录满足condition时,触发器才被执行,否则不执行。Condition中可以通过new对象和old对象不带“:”(注意区别于前面的:new和:old,在代码中引用需要加上冒号)来引用操作的记录。

2、简例
创建测试用表:
create table emp_bak1 as select * from emp;
create table emp_bak2 as select * from emp;

例1:

create or replace trigger insert_emp
  after insert on emp_bak1
  for each row
declare  --Declare后面跟的是本地变量定义部分,如果没有本地变量定义,此部分可以去掉
  test_val emp_bak1.ename%type;--根据表的字段定义变量类型
begin
  dbms_output.put_line('员工编号:'||:new.empno);
  dbms_output.put_line('员工姓名:'||:new.ename);
  dbms_output.put_line('职位:'||:new.job);
  dbms_output.put_line('工资:'||:new.sal);
  dbms_output.put_line('所在部门:'||:new.deptno);
  dbms_output.put_line('---触发器已被执行---');
  --select ename into test_val from emp_bak1 where empno = 7839;--ORA-04091
  select :new.empno into test_val from dual;
  dbms_output.put_line('---测试--->'||test_val);
end;

insert into emp_bak1 (empno, ename, job, sal, deptno) values ('666', 'SM', 'IT', '800', '20');

oracle默认的 用old代表老数据 new代表新数据(这两个变量只有在使用了关键字 "FOR EACH ROW"时才存在;referencing new as new_val old as old_val:这个可以更改新旧值的名字来引用新值,旧值)
insert时 只有new 没有old
delete时 只有old 没有new
update时 二者都可用

create or replace trigger delete_emp
  before delete on emp_bak1 --删除操作前触发
  for each row
begin
  insert into emp_bak2
    (empno, ename, job, sal, deptno)
  values
    (:old.empno, :old.ename, :old.job, :old.sal, :old.deptno);
    dbms_output.put_line('-----有数据删除,员工号为'||:old.empno||'详细信息见emp_bak2表------');
end delete_emp;

insert into emp_bak1 (empno, ename, job, sal, deptno) values ('777', 'K', 'TE', '1000', '30');
delete from emp_bak1 where empno = 777;

例2:指定条件列触发

create or replace trigger tri_01
  after insert or update of sal on emp_bak1
  for each row
begin
  if inserting then
    dbms_output.put_line('新人入驻有收入sal');
  elsif updating then
    dbms_output.put_line('sal有变动');
  end if;
end tri_01;

update emp_bak1 set sal = 888 where empno = 7934;--触发
update emp_bak1 set comm = 666 where empno = 7934;--未触发

注:第二行中的of sal on emp_bak1 是在表emp_bak1的sal字段发生变更时才触发操作,
在触发器主体的if语句表达式中,inserting, updating和deleting可以用来区分当前是在做哪一种DML操作,可以作为把多个类似触发器合并在一个触发器中判别触发事件的属性。

例3:when条件限制

create or replace trigger tri_02
  before update of sal, comm or delete on emp_bak1
  for each row
  when (old.deptno = 30) --注:old前不带':'且结尾不带';'
begin
  case
    when updating('sal') then
      dbms_output.put_line('原来薪资:'||:old.sal||';变更后薪资:'||:new.sal||';');
      if :new.sal < :old.sal then
        dbms_output.put_line('降薪不被允许');
        raise_application_error(-20001, '部门30的人员的工资不能降');
      end if;
    when updating('comm') then
      dbms_output.put_line('原来奖金:'||:old.comm||';变更后奖金:'||:new.comm||';');
      if :new.comm < :old.comm then
        dbms_output.put_line('降奖金不被允许');
        raise_application_error(-20002, '部门30的人员的奖金不能降');
      end if;
    when deleting then
      raise_application_error(-20003, '部门30的人员不能删');
  end case;
end;

select * from emp_bak1 where deptno = 30;
update emp_bak1 set comm = 2000 where empno = 7499;
update emp_bak1 set sal = 20000 where empno = 7698;

raise_application_error相当于拒绝了插入或者修改事务
oracle允许自定义的错误代码的范围为-20000-->20999
raise_application_error(-20001,'ErrorCode');

例4:instead of触发器
instead of 选项使ORACLE激活触发器,而不执行触发事件。只能对视图和对象视图建立instead of触发器,而不能对表、模式和数据库建立instead of 触发器。

--语法类似:
create [or replace] trigger trigger_name
instead of
{insert | delete | update [of column [, column …]]}
on view_name --只能定义在视图上
[referencing {old [as] old_val | new [as] new_val| parent as parent}]--可以给old/new对象赋予新的名称(可以不要)
[for each row ] --因为instead of触发器只能在行级上触发,所以没有必要指定
[when condition]
pl/sql_block | call procedure_name;

视图创建

create view view_emp as
select deptno,count(*) count_no,sum(sal) sal from emp group by deptno;


对基表处理过的视图,在删除时会报下面的错误
ORA-01732: 此视图的数据操纵操作非法
此时可以创建INSTEAD_OF触发器来为 DELETE 操作执行所需的处理,即删除EMP表中所有基准行

create or replace trigger view_tri_03
   instead of delete on view_emp
   for each row
begin
   delete from emp where deptno= :old.deptno;
   dbms_output.put_line('从emp基表中删除部门编号为:'||:old.deptno||'的基础人员数据。');
end view_tri_03;

可看出此触发器只是触发了一个删除部门号的事件,实际更改的还是基表。

例5:语句级触发器

create or replace trigger tri_04
after insert or update of sal on emp_bak1
declare
 v_sumsal number;
begin
  select sum(sal) into v_sumsal from emp_bak1;
 if v_sumsal > 50000 then
  raise_application_error(-20001, '总工资超过50000');
 end if;
end;

--如果用行级触发器(for each row)会报ORA-04091错误

insert into emp_bak1 (empno, ename, job, sal, deptno) values ('777', 'K', 'TE', '90000', '30');

(注:此为学习记录笔记,仅供参考若有问题请指正,后续补充......)

参考资料:https://www.cnblogs.com/wishyouhappy/p/3665851.html

参考资料:https://blog.csdn.net/weiwenhp/article/details/9179891

参考资料:https://www.cnblogs.com/hyq0002013/p/6085981.html

参考资料:https://blog.csdn.net/IndexMan/article/details/8023740

 

猜你喜欢

转载自www.cnblogs.com/shenjie0622/p/10106526.html
今日推荐