--oracle_trigger.sql
触发器是指被隐含执行的存储过程,可以用PL/SQL,java,c进行开发。
触发器由触发事件,触发条件和触发操作三部分组成。
(1)触发事件
指引起触发器被触发的SQL语句,数据库事件或者用户事件。
具体触发事件:
启动和关闭数据库实例
oracle错误消息
用户登录和断开会话
特定表和视图的DML操作
在任何方案上的DDL操作
(2)触发条件(可选)
指使用when子句指定一个BOOLEAN表达式,当布尔表达式为TRUE时,会自动执行触发器相应代码。
(3)触发操作
指包含SQL语句和其他执行代码的PL/SQL块。
限制条件:
1.触发器代码不能超过32K。
2.触发器代码中不能使用long or long raw数据类型。
###基于视图的触发器instead of触发器
###DML触发器包括语句触发器和行触发器
DML需要指定触发时机(before|after),触发事件(insert,update,delete),表名,触发类型,触发条件,触发操作。
触发时机:用于指定触发器的触发时间。before表示执行DML操作之前触发触发器。
触发事件:用于指定导致触发器执行DML操作。
表名:用于指定DML操作所对应的表。
触发类型:用于指定当触发事件发生之后,需要执行几次触发操作。
触发条件:用于指定执行触发器的条件,只有条件为TRUE时才会执行触发器代码。
触发操作:用于指定触发器执行代码。
1.语句触发器
当审计DML操作,或者确保DML操作安全执行时,可以使用语句触发器。语句触发器不能记录列数据的变化。
语法:
create or replace trigger trigger_name
timing event1 [or event2 or event3]
on table_name
pl/sql block;
(1)before语句触发器
//禁止工作人员在周一改变雇员信息
create or replace trigger tr_change_emp
before insert or update or delete
on emp
begin
if to_char(sysdate,'DY','nls_date_language=AMERICAN') IN ('MON') then
--if to_char(sysdate,'DY','nls_date_language=''SIMPLIFIED CHINESE''') IN ('星期一') THEN
raise_application_error(-20001,'You can not change employee infor.');
end if;
end;
当触发器中同时包含多个触发事件时(insert,update,delete).区分具体的触发事件,可以使用3个为此:
inserting,updating,deleting
create or replace trigger tr_change_emp
before insert or update or delete
on emp
begin
if to_char(sysdate, 'DY', 'nls_date_language=AMERICAN') IN ('MON') then
case when inserting then
raise_application_error(-20001, 'You can not insert employee infor.');
when updating then
raise_application_error(-20002, 'You can not update employee infor.');
when deleting then
raise_application_error(-20003, 'You can not delete employee infor.');
end case;
end if;
end;
(2)after语句触发器
//审计emp表上insert,update,delete操作次数
create table t_audit(names varchar2(30) not null primary key,insert_count number,update_count number,delete_count number,start_date date,end_date date);
create or replace trigger tr_audit_emp
after insert or update or delete on emp
declare
v_tmp number;
begin
select count(*) INTO v_tmp from t_audit where names = 'EMP';
if v_tmp = 0 then
insert into t_audit values ('EMP', 0, 0, 0, sysdate, null);
end if;
case
when inserting then
update t_audit
set insert_count = insert_count + 1
where names = 'EMP';
when updating then
update t_audit
set update_count = update_count + 1
where names = 'EMP';
when deleting then
update t_audit
set delete_count = delete_count + 1
where names = 'EMP';
end case;
end;
2.行触发器
行触发器是指执行DML操作时,每作用一行就触发一次的触发器。审计数据变化时,可以使用行触发器。
语法:
create or replace trigger trigger_name
timing event1 [or event2 or event3]
on table_name
[reference OLD AS old|NEW AS new]
FOR EACH ROW
[when condition]
PL/SQL block;
reference:用于指定新,旧数据的方式。默认情况下OLD修饰符引用旧数据,使用NEW修饰符引用新数据。
FOR EACH ROW:表示建立行触发器
(1)before行触发器
//确保雇员工资不低于其原有工资
create or replace trigger tr_update_sal
before update of sal on emp
for each row
begin
if :NEW.sal < :OLD.sal then
raise_application_error(-20001,'salary up');
end if;
end;
(2)
//审计雇员工资的变化
create table t_audit_salary(enames varchar2(50),oldsal number(7,2),newsal number(7,2),create_date timestamp);
create or replace trigger tr_audit_salary
after update of sal on emp
for each row
declare
v_tmp number;
begin
select count(*) into v_tmp from t_audit_salary where enames=:old.ename;
if v_tmp =0 then
insert into t_audit_salary values(:old.ename,:old.sal,:new.sal,sysdate);
else
update t_audit_salary set oldsal=:old.sal,newsal=:new.sal,create_date =sysdate
where enames=:old.ename;
end if;
end;
###系统事件触发器
系统事件触发器指基于oracle系统事件所建立的触发器,提供了跟踪系统内或数据库变化的机制。
常见的系统事件属性函数:
ora_client_ip_address:用于返回客户端的IP地址。
ora_database_name:用于返回当前数据库名。
ora_login_user:用于返回登录用户名。
ora_sysevent:用于返回触发触发器的系统事件名。
//记录用户登录和退出
create table t_login(username varchar2(50),logon_date date,logoff_date date,address varchar2(15));
create or replace trigger tr_login
after logon on database
begin
insert into t_login(username,logon_date,address)
values(ora_login_user,sysdate,ora_client_ip_address);
end;
----
create or replace trigger tr_logoff
before logoff on database
begin
insert into t_login(username,logoff_date)
values(ora_login_user,sysdate);
end;
//记录数据库启动和关闭
create table t_sysevent(events varchar2(50),create_date timestamp);
create or replace trigger tr_startup
after startup on database
begin
insert into t_sysevent values(ora_sysevent,sysdate);
end;
create or replace trigger tr_shutdown
before shutdown on database
begin
insert into t_sysevent values(ora_sysevent,sysdate);
end;
###管理触发器
select TRIGGER_NAME,table_name,status from user_triggers where table_name='EMP';
---禁止触发器
alter trigger trigger_name disable;
---启用触发器
alter trigger TR_STARTUP enable;