首页 > 代码库 > oracle 触发器 学习笔记

oracle 触发器 学习笔记

触发器 是特定事件出现的时候,自动执行的代码块。类似于存储过程,但是用户不能直接调用他们。

功能: 
1、 允许/限制对表的修改 
2、 自动生成派生列,比如自增字段 
3、 强制数据一致性 
4、 提供审计和日志记录 
5、 防止无效的事务处理 
6、 启用复杂的业务逻辑 
开始 
create trigger biufer_employees_department_id 
before insert or update 
of department_id 
on employees 
referencing old as old_value 
new as new_value 
for each row 
when (new_value.department_id<>80 ) 
begin 
:new_value.commission_pct :=0; 
end; 

触发器的组成部分: 
1、 触发器名称 
2、 触发语句 
3、 触发器限制 
4、 触发操作 
1、 触发器名称 
create trigger biufer_employees_department_id 
命名习惯: 
biufer(before insert update for each row) 
employees 表名 
department_id 列名 
2、 触发语句 
比如: 
表或视图上的DML语句 
DDL语句 
数据库关闭或启动,startup shutdown 等等 
before insert or update 
of department_id 
on employees 
referencing old as old_value 
new as new_value 
for each row 
说明: 
1、 无论是否规定了department_id ,对employees表进行insert的时候 
2、 对employees表的department_id列进行update的时候 
3、 触发器限制 
when (new_value.department_id<>80 ) 
限制不是必须的。此例表示如果列department_id不等于80的时候,触发器就会执行。 
其中的new_value是代表跟新之后的值。 
4、 触发操作 
是触发器的主体 
begin 
:new_value.commission_pct :=0; 
end; 
主体很简单,就是将更新后的commission_pct列置为0 
触发: 
insert into employees(employee_id, 
last_name,first_name,hire_date,job_id,email,department_id,salary,commission_pct ) 
values( 12345,‘Chen‘,‘Donny‘, sysdate, 12, ‘donny@hotmail.com‘,60,10000,.25); 
select commission_pct from employees where employee_id=12345; 
触发器不会通知用户,便改变了用户的输入值。 
触发器类型: 
1、 语句触发器 
2、 行触发器 
3、 INSTEAD OF 触发器 
4、 系统条件触发器 
5、 用户事件触发器 
1、 语句触发器 
是在表上或者某些情况下的视图上执行的特定语句或者语句组上的触发器。能够与INSERT、UPDATE、 
DELETE或者组合上进行关联。但是无论使用什么样的组合,各个语句触发器都只会针对指定语句激活一次 
。比如,无论update多少行,也只会调用一次update语句触发器。 
例子: 
需要对在表上进行DML操作的用户进行安全检查,看是否具有合适的特权。 
Create table foo(a number); 
Create trigger biud_foo 
Before insert or update or delete 
On foo 
Begin 
If user not in (‘DONNY‘) then 
Raise_application_error(-20001, ‘You don‘t have access to modify this table.‘); 
End if; 
End; 

即使SYS,SYSTEM用户也不能修改foo表 
[试验] 
对修改表的时间、人物进行日志记录。 
1、 建立试验表 
create table employees_copy as select *from hr.employees 
2、 建立日志表 
create table employees_log( 
who varchar2(30), 
when date); 
3、 在employees_copy表上建立语句触发器,在触发器中填充employees_log 表。 
Create or replace trigger biud_employee_copy 
Before insert or update or delete 
On employees_copy 
Begin 
Insert into employees_log( 
Who,when) 
Values( user, sysdate); 
End; 

4、 测试 
update employees_copy set salary= salary*1.1; 
select *from employess_log; 
5、 确定是哪个语句起作用? 
即是INSERT/UPDATE/DELETE中的哪一个触发了触发器? 
可以在触发器中使用INSERTING / UPDATING / DELETING 条件谓词,作判断: 
begin 
if inserting then 
----- 
elsif updating then 
----- 
elsif deleting then 
------ 
end if; 
end; 
if updating(‘COL1‘) or updating(‘COL2‘) then 
------ 
end if; 
[试验] 
1、 修改日志表 
alter table employees_log 
add (action varchar2(20)); 
2、 修改触发器,以便记录语句类型。 
Create or replace trigger biud_employee_copy 
Before insert or update or delete 
On employees_copy 
Declare 
L_action employees_log.action%type; 
Begin 
if inserting then 
l_action:=‘Insert‘; 
elsif updating then 
l_action:=‘Update‘; 
elsif deleting then 
l_action:=‘Delete‘; 
else 
raise_application_error(-20001,‘You should never ever get this error.‘); 
Insert into employees_log( 
Who,action,when) 
Values( user, l_action,sysdate); 
End; 

3、 测试 
insert into employees_copy( employee_id, last_name, email, hire_date, job_id) 
values(12345,‘Chen‘,‘Donny@hotmail‘,sysdate,12); 
select *from employees_log 
update employees_copy set salary=50000 where employee_id = 12345; 
2、 行触发器 
是指为受到影响的各个行激活的触发器,定义与语句触发器类似,有以下两个例外: 
1、 定义语句中包含FOR EACH ROW子句 
2、 在BEFORE……FOR EACH ROW触发器中,用户可以引用受到影响的行值。 
比如: 
定义: 
create trigger biufer_employees_department_id 
before insert or update 
of department_id 
on employees_copy 
referencing old as old_value 
new as new_value 
for each row 
when (new_value.department_id<>80 ) 
begin 
:new_value.commission_pct :=0; 
end; 

Referencing 子句: 
执行DML语句之前的值的默认名称是 :old ,之后的值是 :new 
insert 操作只有:new 
delete 操作只有 :old 
update 操作两者都有 
referencing子句只是将new 和old重命名为new_value和old_value,目的是避免混淆。比如操作一个名为 
new的表时。 
作用不很大。 
[试验]:为主健生成自增序列号 
drop table foo; 
create table foo(id number, data varchar2(20)); 
create sequence foo_seq; 
create or replace trigger bifer_foo_id_pk 
before insert on foo 
for each row 
begin 
select foo_seq.nextval into :new.id from dual; 
end; 

insert into foo(data) values(‘donny‘); 
insert into foo values(5,‘Chen‘); 
select * from foo; 
3、 INSTEAD OF 触发器更新视图 
Create or replace view company_phone_book as 
Select first_name||‘, ‘||last_name name, email, phone_number, 
employee_id emp_id 
From hr.employees; 
尝试更新email和name 
update hr.company_phone_book 
set name=‘Chen1, Donny1‘ 
where emp_id=100 
create or replace trigger update_name_company_phone_book 
INSTEAD OF 
Update on hr.company_phone_book 
Begin 
Update hr.employees 
Set employee_id=:new.emp_id, 
First_name=substr(:new.name, instr(:new.name,‘,‘)+2), 
last_name= substr(:new.name,1,instr(:new.name,‘,‘)-1), 
phone_number=:new.phone_number, 
email=:new.email 
where employee_id=:old.emp_id; 
end; 
4、 系统事件触发器 
系统事件:数据库启动、关闭,服务器错误 
create trigger ad_startup 
after startup 
on database 
begin 
-- do some stuff 
end; 

5、 用户事件触发器 
用户事件:用户登陆、注销,CREATE / ALTER / DROP / ANALYZE / AUDIT / GRANT / REVOKE / 
RENAME / TRUNCATE / LOGOFF 
例子:记录删除对象 
1. 日志表 
create table droped_objects( 
object_name varchar2(30), 
object_type varchar2(30), 
dropped_on date); 
2.触发器 
create or replace trigger log_drop_trigger 
before drop on donny.schema 
begin 
insert into droped_objects values( 
ora_dict_obj_name, -- 与触发器相关的函数 
ora_dict_obj_type, 
sysdate); 
end; 

3. 测试 
create table drop_me(a number); 
create view drop_me_view as select *from drop_me; 
drop view drop_me_view; 
drop table drop_me; 
select *from droped_objects 
禁用和启用触发器 
alter trigger <trigger_name> disable; 
alter trigger <trigger_name> enable; 
事务处理: 
在触发器中,不能使用commit / rollback 
因为ddl语句具有隐式的commit,所以也不允许使用 
视图: 
dba_triggers

本文出自 “IT精英的集中区” 博客,请务必保留此出处http://msuccess.blog.51cto.com/5486886/1416449