触发器就是在做 a 事件后,再自动的做 b 事件。触发器的要点是:什么时候触发(之前还是
之后),触发后怎么干(行触发还是语句级触发),干什么(程序模块中处理)。
使用触发器的目的:
维护数据库的完整性
一个操作后做其它连带的操作
通过视图改基表
审计数据库的操作
构建实验表
connect scott/tiger
drop table d purge;
drop table e purge;
create table d as select * from dept;
create table e as select * from emp;
Select * from d;
Select * from e;
感受触发器
CREATE or replace TRIGGER d_update
AFTER delete or UPDATE OF deptno ON d
FOR EACH ROW
BEGIN --当 D 表的部门号修改的时候 E 表的对应部门号也相应的修改
IF (UPDATING AND :old.deptno != :new.deptno)
THEN UPDATE e
SET deptno = :new.deptno
WHERE deptno = :old.deptno;
END IF;
--当 D 表的某个部门号删除的时候,E 表的对应部门同时被删除
if deleting then
delete e where deptno=:old.deptno;
end if;
END;
/
--验证触发器的状态
select trigger_name,status from user_triggers;
--改变触发器的状态
--禁用某个触发器
ALTER TRIGGER d_update disable;
--禁用某个表上的所有触发器
alter table d disable all triggers;
--删除触发器
DROP TRIGGER d_update;
验证 d_update 的功能
update d set deptno=50 where deptno=30;
select * from e;
select * from d;
delete d where deptno=20;
select * from e;
select * from d;
Commit;
触发器的类型
行级触发 FOR EACH ROW
影响的每一行都会执行触发器
语句级触发
默认的模式,一句话才执行一次触发器
触发器不能嵌套,不能含有事物控制语句
何时触发
Before 触发类型:在条件运行前,执行触发器
After 触发类型:在条件运行后,执行触发器
INSTEAD OF 触发类型:替代触发,作用在视图上
例如禁止对表 E 的 SAL 列进行修改的小程序:
create or replace trigger e_update
before update of sal on e
begin
if updating then
raise_application_error(-20001,'工资不能被改动');
end if;
end;
/
例如保存老值和新的值的程序:
CONNECT SCOTT/TIGER
DROP TABLE T1;
CREATE TABLE T1 AS SELECT SAL OLD_VALUE,SAL NEW_VALUE FROM EMP WHERE 0=9;
CREATE OR REPLACE TRIGGER TRG1
BEFORE INSERT OR UPDATE OF sal ON emp
FOR EACH ROW
BEGIN
INSERT INTO T1 VALUES(:OLD.SAL,:NEW.SAL);
END;
/
SELECT * FROM T1;
update emp set sal=sal+1;
commit;
select * from t1;
建立一个不可通过视图来改基表的视图 V1
drop table e1;
create table e1 as select * from emp;
drop view v1;
create view v1 as
select distinct deptno from e1;
--试图修改 V1 时报错
update v1 set deptno=50 where deptno=10;
建立一个替代触发器,当修改 V1 的时候会自动的修改基表
create or replace trigger trigger_instead_of
instead of insert or update or delete on v1
for each row
begin
if updating then
update e1 set deptno=:new.deptno where deptno=:old.deptno;
end if;
end;
/
建立一个登录的审计触发器
conn scott/tiger
drop table login_table;
create table login_table(user_id varchar2(15),log_date date,action varchar2(15));
--on schema 方式为只记录当前的用户行为
CREATE OR REPLACE TRIGGER logon_trig
AFTER LOGON ON SCHEMA
BEGIN
INSERT INTO login_table(user_id, log_date, action)
VALUES (USER, SYSDATE, 'Logging on');
END;
/
CREATE OR REPLACE TRIGGER logoff_trig
BEFORE LOGOFF ON SCHEMA
BEGIN
INSERT INTO login_table(user_id, log_date, action)
VALUES (USER, SYSDATE, 'Logging off');
END;
/
conn scott/tiger
conn hr/hr
conn scott/tiger
select user_id, to_char(log_date,'yyyy/mm/dd:hh24:mi:ss') log_date, action from
login_table;
--删除触发器
drop trigger logon_trig;
drop trigger logoff_trig;