Oracle-触发器
触发器可以看做一种“特殊”的存储过程,它定义了一些与数据库相关事件(INSERT,UPDATE,CREATE)发生时应执行的“功能代码块”,通常用于管理复杂的完整性约束,或监控对表的修改,或通知其他程序,甚至可以实现对数据的审计功能。
触发事件:能够引起触发器运行的操作被称为“触发事件”,如执行DML(INSERT,UPDATE,DELETE),DDL(CREATE,ALTER.DROP);引发数据库系统事件(系统启动或退出,产生异常错误);引发用户事件(登陆或退出数据库操作)
根据触发器的触发事件和触发器的执行情况,Oracle所支持的触发器分为一下5种类型:
1行级触发器:当DML语句对每一行数据进行操作时都会引起该触发器的运行
2语句级触发器:无论DML语句影响多上行数据,其所引起的触发器仅执行一次
3替换触发器:该触发器是定义在视图上的,而不是定义在表上,它是用来替换所使用实际语句的触发器
4用户事件触发器:与DDL操作或用户登陆、退出数据库事件相关的触发器。
5.系统事件触发器:指Oracle数据库系统的事件中进行触发的触发器,如Oracle实例的启动与关闭
语句级触发器:
例子:在SCOTT模式下,创建dept_log数据表,并在其中定义两个字段,分别用来存储操作种类信息和操作日期:
create table dept_log
(
operate_tag varchar2(10),
operate_tiem date
);
创建一个关于emp表的语句级触发器,将用户对dept表的操作信息保存到dept_log表中:
create or replace trigger tri_dept
before insert or update or delete
on dept
declare
var_tag varchar2(10);
begin
if inserting then
var_tag:='插入';
elsif updating then
var_tag:='修改';
elsif deleting then
var_tag:='删除';
end if;
insert into dept_log
values(var_tag,sysdate);
end tri_dept;
/
执行触发器,也就是触发这些事件(insert,update,delete);之后再查看dept_log表就可以观察到结果
行级触发器:
例子 :在SCOTT模式下,创建一个用于存储商品种类的数据表,其中包括商品序号列和商品名称列:
create table goods(
id int primary key,
good_name varchar2(50));
创建一个序列:
create sequence seq_id;
创建一个触发器,用于为goods表的id赋值
create or replace trigger tri_insert_good
before insert
on goods
for each row
begin
select seq_id.nextval
into :new.id
from dual;
end;
/
:new.id--列标识符
有两种列标识符,
原值标识符:--:old.id --一般在update delete
新值标识符:--:new.id--一般在update insert
触发该触发器:
可以通过插入语句 insert into goods(good_name) values('苹果');
同时用insert into goods(id,good_name)values (9,'葡萄');
然后再查询该表即可知道是否,自动插入了id
但是第二条记录的id,还是会顺序增长,那是因为,触发器将seq_id的nextval值赋给了:new.id,并且nextval属性值是连续不间断的
替换触发器:
例子:首先创建一个视图
(首先该用户要有创建视图的权限,切换到system ,grant create view to scott)
create view view_emp_dept
as
select empno,ename,dept.deptno,dname,job,hiredate from emp,dept
where emp.deptno=dept.deptno;
注意:在没有创建“替换触发器”时,试图向该视图中插入数据,是会有错误的ORA-01776:无法通过连接视图修改多个基表
创建一个关于view_emp_dept视图的替换触发器,在该触发器的主体中实现向emp表和dept表中插入两行相互关联的数据
create or replace trigger tri_insert_view
instead of insert
on view_emp_dept
for each row
declare
row_dept dept%rowtype;
begin
select * into row_dept from dept where deptno=:new.deptno;
if sql%notfound then
insert into dept(deptno,dname) values(:new.deptno,:new.dname);
end if;
insert into emp(empno,ename,deptno,job,hiredate) values
(:new.empno,:new.ename,:new.deptno,:new.job,:new.hiredate);
end tri_insert_view;
/
触发该触发器:
insert into view_emp_dept(empno,ename,deptno,dname,job,hiredate)
values(8888,'东方',10,'ACCOUTNTING','CASHIER',sysdate);
这样,便可以插入一条记录到视图;
但是,如果这个deptno不在dept表中,那么会在dept表中插入相关记录,但是,测试时,却出现了错误
用户事件触发器:
因进行DDL操作或用户登录、退出操作而引起运行的一种触发器,比如CREATE,ALTER,DROP,ANALYZE,COMMENT,GRANT,REVOKE,RENAME,TRUNCATE,SUSPEND,LOGON ,LOGOFF
创建一个日志信息表,用于保存DDL操作的信息,包括数据对象,数据对象类型,操作行为,操作用户,操作日期
create table ddl_oper_log
(
db_obj_name varchar2(20),
db_obj_type varchar2(20),
oper_action varchar2(20),
oper_user varchar2(20),
oper_date date);
关于scott用户的DDL操作(CREATE,ALTER,DROP),创建一个触发器,然后将DDL操作的相关信息插入到ddl_oper_log日志表中
create or replace trigger tri_ddl_oper
before create or alter or drop
on scott.schema
begin
insert into ddl_oper_log values(
ora_dict_obj_name,--获取DDL操作对象的名称
ora_dict_obj_type,--获取DDL操作所对应的数据库对象的类型
ora_sysevent,--获取触发器的系统事件名称
ora_login_user,--获取登陆用户名
sysdate);
end;
/
触发触发器:
create,alter,drop 然后再select * from ddl_oper_log;