oracle之触发器

触发器语法:

1、触发器语法

CREATE [OR REPLACE] TIGGER 触发器名

[before|after] --触发时间

[insert|update[of]|delete] --触发事件

ON 表名

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

[for each statement]--表级触发器


BEGIN

    pl/sql语句[或者调用已经建立好的存储过程]

END;

其中:

触发器名:触发器对象的名称。

由于触发器是数据库自动执行的,因此该名称只是一个名称,没有实质的用途。

触发时间:指明触发器何时执行,该值可取:

before---表示在数据库动作之前触发器执行;

after---表示在数据库动作之后出发器执行。

触发事件:指明哪些数据库动作会触发此触发器:

insert:数据库插入会触发此触发器;

update:数据库修改会触发此触发器;

delete:数据库删除会触发此触发器。

表 名:数据库触发器所在的表。

for each row:对表的每一行触发器执行一次。

for each statement:语句级触发器,则只对整个表执行一次。


具体举例:


先建两个表emp(员工表,员工号,所在部门号,名字,职位,工资)和dept(部门表,部门号,部门名称)

create table emp(empno char(4) constraint pk_emp_empno primary key,
deptno number(1) constraint fk_emp_dept_deptno references dept(deptno),
ename varchar(12),
job varchar(12),
sal number
);


create table dept(deptno number(1) constraint pk_dept_deptno primary key,
dname varchar2(20));

1:建立触发器当删除EMP1 表中的某条记录时,把被删除记录写到职工表删除日志表中去
create table emp_his as select * from emp1 where 1=2;

create or replace trigger emp_trigger
before delete on emp1
for each row
begin
insert into emp_his values(:old.empno,:old.deptno,:old.ename,:old.job,:old.sal);
end;

drop table emp_his;
drop trigger emp_trigger;

2:建立触发器在非工作时间不能对dept表进行修改

create or replace trigger dept_trigger
before insert or delete or update on dept
begin
if(to_char(sysdate,'DAY') in('星期六','星期日')) or (to_char(sysdate,'HH24:MI') not between '08:00' and '18:30') then
    raise_application_error(-20001,'不是上班时间,不能更改dept表数据');
end if;
end;


drop trigger dept_trigger;



3:限定只对在sale部门的emp员工记录进行行触发器操作。

create or replace trigger emp_trigger
before delete or insert or update on emp
for each row
when (old.deptno=2 or new.deptno=2)/*指定了某个属性值触发*/
begin
case
when updating('sal') then
 if(:old.sal<=:new.sal) then
   raise_application_error(-20001,'sale 部门的人的工资不能下降');
  end if;
when inserting then
  if(:new.sal<=3000) then
    raise_application_error(-20002,'sale部门的人工资不能下降');
  end if;
when deleting then
   raise_application_error(-20003,'sale 部门的人不能删除');
end case;
end;

 

insert into emp values('2222',2,'回火','saleman',2000);

drop trigger emp_trigger;


/*
create or replace trigger emp_trigger
before delete  or insert or update of sal on emp /*指定某属性列触发*/
for each row

begin
case
when updating('sal') then
 if(:old.sal<=:new.sal) then
   raise_application_error(-20001,'sale 部门的人的工资不能下降');
  end if;
when inserting then
  if(:new.sal<=3000) then
    raise_application_error(-20002,'sale部门的人工资不能下降');
  end if;
when deleting then
   raise_application_error(-20003,'sale 部门的人不能删除');
end case;
end;

*/


4:当某表的主键删除一条含主键的记录时,级联删除相关的外键记录,当删除dept表中的某条记录时
级联删除emp1表中deptno相同的记录

create or replace trigger emp_trigger
before delete or update of deptno on dept
for each row
begin
case
when deleting then
  delete from emp where deptno=:old.deptno;
when updating then
  update emp set deptno=:new.deptno where deptno=:old.deptno;
end case;
end;







5:在触发器里调用过程,每当改变emp表的员工号时或部门号时,将该原纪录插入到emp_history 表中
create table emp_history as select * from emp where 1=2;

create or replace procedure add_emp_history(
p_empno emp.empno%type,
p_deptno emp.deptno%type,
p_ename emp.ename%type,
p_job emp.job%type,
P_sal emp.sal%type
)

is

begin
insert into emp_history values(p_empno,p_deptno,p_ename,p_job,p_sal);
end;
 
create or replace trigger update_emp_history
after update or delete of empno,deptno on emp
for each row
begin
add_emp_history(:old.empno,:old.deptno,:old.ename,:old.job,:old.sal);
end;

drop trigger update_emp_history;
drop procedure add_emp_history;





                            对视图进行触发操作
instead of 行级触发器,用于对视图的DML触发,由于视图有可能是由多个表进行联结(join)
而成,因而并非是所有的联结都是可更新的。但可以按照所需的方式执行更新,例如下面情况:



create or replace view emp_view as select
deptno,count(*)total_employee,sum(sal)sum_sal from emp group by deptno;


1:当对该视图进行DML操作,如delete from emp_view where deptno=1 会报错,非法
可以建立instead of 触发器来删除emp表中的基准行,是之删除成功

create or replace triggrt emp_view_trigger
instead of
delete on emp_view
for each row
begin
delete from emp where deptno=:old.deptno;
end;




案例1:
实施复杂的安全性检查,禁止在非工作时间插入新员工
周末或者时间不在8:00-18:00
sql
怎么判断周末
select to_char(sysdate,day) from dual;
怎么判断时间不在8:00-18:00
to_number(systade,'hh24') not between 8 and 18

变量:
星期:(sysdate,'day')
时间:(sysdate,'hh24')


create or replace trigger emp_tri
before insert on emp
begin
if  (to_char(sysdate,'day') in('星期六,星期日')) or (to_number(to_char(sysdate,'hh24')) not between 8 and 18) then
  raise_application_error(-20001,'非工作时间,不能对emp表进行人员插入');
end if;
end;



案例2:数据的确认
应该是行级触发器
sql语句


变量



create or replace trigger emp_tri
before update on emp
for each row
begin
if :new.sal<:old.sal then
 raise_application_error(-20002,'更新错误,更新后工资薪水不能低于之前的工资');
end if;
end;



案例3:触发器的审计功能
基于值的审计功能,给员工涨工资+20,当工资>=3330时,插入到表 emp_sal中


先建表:create table emp_sal (empno char(4) primary key,sal number);

create or replace trigger emp_tri
before update of sal on emp
for each row

begin
if :new.sal>3330 then
insert into emp_sal values(:old.empno,:new.sal);
end if;
end;


案例4:利用触发器实现数据的备份与同步
在一台机器上模拟分布式数据库系统实现数据备份与同步
每当给一个员工涨完工资后,自动备份到备份表中
先建一个备份表:create table emp_copy as select * from emp;


create or replace trigger emp_tri
after update on emp
for each row
begin
update emp_copy set sal=:new.sal where empno=:old.empno;
end;


案例五:当规定全体员工的工资不能超过某个值(10000000)时,无法通过行级触发器完成(行级触发器只能定位到某一行,无法对整个表进行查询),这时需要用到语句级触发器

create or replace trigger max_total_sal

before insert or update of sal on emp

for each statement

declare

total_sal nmber;

begin

select sum(sal) into total_sal from emp;

if(total_sal>10000000)

raise_application_error(-20001,'员工总工资超过限定值');

end if;

end;












猜你喜欢

转载自blog.csdn.net/zhu0902150102/article/details/80974091