========================触发器========================
特殊的子程序: --声明变量时:declare 不是as/is
1.触发器的执行条件
触发事件:
DML+DDL....
Insert、Delete、Update、Create、Alter、Drop、Grant ......
触发时机:
触发器是在某个触发事件前还是后执行 (before/after...)
触发对象:
只有对特定的对象操作,触发器才有可能触发 (on...)
触发类型:
语句级还是行级
语句级:触发事件执行一次就触发一次(只关心触发事件的类型)
行级:触发事件在具体执行时,每操作一行就触发一次(不但关系类型,还关系对行的影响)(for each row)
触发条件:
触发器在满足以上所有条件以外,还要满足的额外条件 (when...)
条件谓词:
触发器中的语法元素
Inserting、Updating、Deleting等
2.应用时机:
实现商业规则和企业逻辑的方法很多,可以使用约束、触发器、子程序(过程和函数)。
1、约束性能{zh0},实现也最简单,所以{sx}约束。
2、其次是触发器。
3、{zh1}才是子程序
4、应用程序
3.分类:
1.语句级
--以一个完整的DML语句为单位执行触发
--与DML语句影响的行数无关
--语句级触发器,不可以记录列数据的变化,只能审计DML操作或确保DML操作安全执行
2.行级
--由DML语句执行的DML操作所影响的行为单位触发
--可能执行多次,因为一个DML语句可能操作多行
--行级触发器可以访问列值
--:old / :new 行级独有
在PL/SQL块或SQL语句中应用时,前面要加‘:’,但是,在when condition子句中不用加
3.替代触发器
可更新视图:可以在其上执行DML语句的视图,可更新视图不包含以下内容:
集合操作、聚集函数、分组、xx重复、连接操作
注意:
--不能指定before/after选项
--必须指定for each row选项
--没有必要针对一个表的视图创建替代触发器
4.其他操作:
数据字典:user_triggers
禁止触发器
alter trigger trigger_name disable;
xx触发器
alter trigger trigger_name enable;
禁止/xx表上的全部触发器
alter table table_name disable all triggers;
alter table table_name enable all triggers;
重新编译触发器
alter trigger trigger_name compile;
删除触发器
drop trigger trigger_name
6.注意问题:
触发器中不可以包含事务控制语句
触发器调用的过程、函数都不能包含事务控制语句
在触发器主体中不可以声明LOB、LONG或LONG RAW类型的变量
触发器不可以接受参数
触发器{zd0}不得超过32K
一个表上最多可以创建12个触发器
7.范例:
1.语句级:
----------------------------应用范例:安全性控制-----------------------------
--创建触发器,阻止用户在非工作时间操作emp中的任何数据
Create or replace trigger tr_emp_time
Before insert or update or delete
On emp
Begin
if
(to_char(sysdate,'day') in ('星期六','星期天')) or
(to_char(sysdate,'hh24') not between 8 and 18)
then
raise_application_error(-20001,'不是上班时间,不能修改emp表');
end if;
End;
2.行级:
1、==自动编号实现==
.....
2、====销售人员工资不能降低,销售人员补助不能降,销售人员纪录不能删除===
Create or replace trigger tr_emp_sal_comm
Before update of sal,comm or delete
on emp
For each row
When (old.job=‘SALESMAN’)
Begin
case
when updating(‘sal’) then
if :new.sal<:old.sal then
raise_application_error(-20001,’销售人员工资不能降’);
end if;
when updating(‘comm’) then
if :new.comm<:old.comm then
raise_application_error(-20002,’销售人员补助不能降’);
end if;
when deleting then
raise_application_error(-20003,’销售人员纪录不能删除’);
end case;
End;
3.============行级触发器实现数据备份=============
解雇员工时,需要把员工的详细信息在emp表中删除,为了保留此信息,以备于以后使用,我们通过
触发器实现,当删除一名员工时,自动的把这个员工的信息放置到解雇员(fire_emp)工表中.
create table fire_emp as select * from emp;
delete from fire_emp;
create or replace trigger fire_emp_tri
after delete
on emp
for each row
begin
insert into fire_emp
values(:old.ENAME,:old.SEX,:old.ID,:old.SALARY,:old.CITY,:old.BIRTHDAY,:old.ADDRESS,:old.DNO,:old.PNO);
end fire_emp_tri;
4.===========行级触发器实现级联删除================
利用触发器实现,当删除一个部门时,自动把部门的员工全部删除
先对部门表和员工表数据备份,在两个备份表上作实验
create table BK_emp as select * from emp;
create table BK_dept as select * from dept;
create or replace trigger remove_dept
after delete
on BK_dept
for each row
begin
delete from BK_emp where dno=:old.dno;
end remove_dept;
select * from bk_emp where dno=1;
delete from bk_dept where dno=1;
select * from bk_emp where dno=1;
5.============行级触发器实现级联更新=============
利用触发器实现,当修改一个部门的编号,自动的把员工的部门编号也一起更改过来。
create or replace trigger e_d_tri
after update of dno
on bk_dept
for each row
begin
update bk_emp set dno=:new.dno where dno=:old.dno;
end e_d_tri;
6.==================生成流水号==================
--创建表
create table codes(uname varchar2(20), code varchar(50));
--创建序列
create sequence seq_code;
--创建触发器实现,插入uname时自动生成流水号:系统时间+自增长列+uname
create or replace trigger tri_code
before insert on codes
for each row
declare
v_num int;
begin
select seq_code.nextval into v_num from dual;
:new.code:=to_char(sysdate,'YYMMDDHH24MISS')||v_num||:new.uname;
end;
select * from codes;
insert into codes(uname) values('hemes');
drop trigger tri_code;
3.替代
详见13-PLSQL高级-2-范例