三、DML触发器
1.控制数据安全
案例01:
/*
限制用户只能在工作时间8:00到17:00修改表apple中的数据
*/

create or replace trigger tr_work_apple
before insert or update or delete on apple
begin
 if to_char(SYSDATE, 'HH24')  not between 9 and 17 then
 raise_application_error(-20001,'不能在非工作时间修改该表数据');
 end if;
end;

 


2.实现数据审计
/*
审计可以用于监视非法和可疑的数据库活动。
*/

案例参考前面的数据审计部分;

 

3.实现数据完整性
/*

希望员工的新工资不能低于原来的工资并且增幅不能超过20%

*/
create or replace trigger tr_check_emp_sal
before update of sal on emp_sal
for each row
when (new.sal<old.sal or new.sal>1.2*old.sal)
begin
 raise_application_error(-20011,'工资只能增不降,并且增幅不能超过20%!');
end;

 

4.实现参照完整性
环境表:
create table p01
(sid int not null,
name varchar2(10)
);


create table p02
(
sid int,
score int
);

alter table p01
add constraint pk01 primary key(sid);

alter table p02
add constraint fk01 foreign key(sid) references p01 (sid);


insert into p01 values (1001, 'wind');
insert into p01 values (1002, 'snow');
insert into p01 values (1003, 'apple');
insert into p01 values (1004, 'mary');

insert into p02 values (1001, 99);
insert into p02 values (1002, 85);
insert into p02 values (1003, 96);
insert into p02 values (1004, 100);


问题:

当p01表更新数据时由于不能级联更新子表所以报错:

SQL> update p01 set sid=101 where name='wind';
update p01 set sid=101 where name='wind'
*
ERROR 位于第 1 行:
ORA-02292: 违反完整约束条件 (SCOTT.FK01) - 已找到子记录日志


解决:使用触发器实现级联更新
create or replace trigger tr_update_cascade_p01
after update of sid on p01
for each row
begin
update p02 set sid=:new.sid where sid=:old.sid;
dbms_output.put_line('子表也同时级联更新!');
end;

 

---------------------------------------------------------------
****************************************************************
四、替代触发器
****************************************************************
--------------------------------------------------------------
/*
对于简单的视图我们可以通过insert、update、delete操作,但是对于复杂的视图则不允许执行这些操作;
当满足下列任意一个条件时都不允许执行DML操作:
1.具体集合操作(union、union all、intersect、minus)
2.具有分组函数(min、max、sum、avg、count等)
3.具有group by、connect by、start with
4.具有distinct关键字
5.具有连接查询

为了使用DML语句修改表,需要使用替代触发器,但是建立instead of触发器有以下注意事项:
1.instead of只适用于视图
2.当基于视图建立触发器时不能指定before和after选项
3.在建立视图时没有指定with chekc option
4.当建立触发器时必须指定for each row

*/

 


--案例01:替代触发器
1)替代触发器子能应用于行级
A.新建视图
create or replace view v01
as
select stu.stuid, stu.stuname, sub.subjectid, sub.subjectname,
sc.score from student stu, subject sub, score sc
where stu.stuid=sc.stuid and sc.subjectid=sub.subjectid;

B、新建替代触发器
create or replace trigger tr02
instead of insert on v01
referencing new n
for each row
declare
  icount int;
begin
select count(*) into icount from student where stuid=:n.stuid;
if icount=0 then
  insert into student (stuid, stuname) values (:n.stuid, :n.stuname);
else
  update student set student.stuname=:n.stuname where stuid=:n.stuid;
end if;
select count(*) into icount from subject where subjectid=:n.subjectid;
if icount=0 then
  insert into subject values (:n.subjectid, :n.subjectname);
else
  update subject set subject.subjectname=:n.subjectname where   subjectid=:n.subjectid;
end if;
select count(*) into icount from score where subjectid=:n.subjectid and stuid=:n.stuid;
if icount=0 then
  insert into score values (:n.stuid, :n.subjectid, :n.score);
else
  update score set score.score=:n.score where subjectid=:n.subjectid and stuid=:n.stuid;
end if;
end;


C.测试