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;

例子:

CREATE OR REPLACE PACKAGE aae AS
TYPE cur_sor IS REF CURSOR;--声明一个cursor的游标

PROCEDURE showsalsu(dept_id NUMBER,ab OUT CUR_SOR);

END aae;(程序包)

CREATE OR REPLACE PACKAGE BODY aae AS
PROCEDURE showsalsu(dept_id NUMBER,ab OUT CUR_SOR)AS
a employees%ROWTYPE;
BEGIN
OPEN ab FOR SELECT * FROM employees e WHERE e.department_id=dept_id;打开游标并把值给游标

LOOP
FETCH ab INTO a ;--取值
EXIT WHEN ab%NOTFOUND;
dbms_output.put_line(a.last_name);

END LOOP;
END;
END aae;

原文地址:https://www.cnblogs.com/gaofangquan/p/7382846.html