触发器

复习——用check短语满足用户的要求

例子:创建Student2表,要求Ssex只允许取“男”或“女”。
    CREATE TABLE Student2
        (Sno  varchar2(9) PRIMARY KEY,
          Sname varchar2(8) NOT NULL,                     
          Ssex   varchar2(2)  CHECK (Ssex IN (‘男’,‘女’) ) ,                
          Sage  SMALLINT,
          Sdept  varchar2(20)
        );  

一、DML触发器(触发器的触发事件为DML语句insert  or  update   or delete)

1.创建一个触发器,当XS表中记录被删除时,请备份下删除的记录,方式:写到新建表XS_1中,以备查看。

//创建表 xs_1,搭建平台(只保留学生表的结构)
create table xs_1 as select * from xs;
truncate table xs_1;

//创建触发器
create trigger t1
 before delete on xs
   for each row
declare
begin
  insert into xs_1(xh,xm,zym,xb,cssj,zxf,bz) values(:old.xh,:old.xm,:old.zym,:old.xb,:old.cssj,:old.zxf,:old.bz);
end t1;

//调用
delete from xs where xh='001';
select * from xs;
select * from xs_1;

2.监控用户对XS表的操作,要求:当XS表执行插入、更新和删除3种操作后在sql_info表中给出相应提示和执行时间。

//创建sql_info表
create table sql_info(info varchar(10),time date);

create or replace trigger t2
  after update or delete or insert on xs
    for each row
declare
   v_info sql_info.info%type;
begin
  if inserting then v_info:='插入';
  elsif updating then v_info:='更新';
  else  v_info:='删除';
  end if;
  insert into sql_info values(v_info,sysdate);
end t2;
  

delete from xs where xh='101112'; //调用

3.当插入新员工时显示新员工的员工号、员工名;当更新员工工资时,显示修改前后员工工资;当删除员工时,显示被删除的员工号、员工名。

create or replace trigger t3
  after update or insert or delete on scott.emp
    for each row
begin
  if inserting then dbms_output.put_line(:new.ename||' '||:new.empno); //新员工号表示方法
  elsif updating then dbms_output.put_line(:old.sal||' '||:new.sal);
  else dbms_output.put_line(:old.empno||' '||:old.ename);
  end if;
end t3;


Set serveroutput on
declare 
begin
    update scott.emp set sal=7777 where empno=7788;
  commit;
end;

4.此例为语句级触发器
针对Scott.emp表,记录其相应操作的信息,具体如下:
当执行插入操作时,统计操作后员工人数;
当执行更新工资操作时,统计更新后员工平均工资;
当执行删除操作时,统计删除后各个部门剩余的人数(游标)。

create or replace trigger t4
  after update or insert or delete on scott.emp
declare
  v1 number; 
  v2 scott.emp.sal%type;
begin
  if inserting then 
    select count(*) into v1 from scott.emp;
    dbms_output.put_line('添加记录后总人数为'||v1);
  elsif updating then 
    select avg(sal) into v2 from scott.emp;
    dbms_output.put_line('更新记录后平均工资为'||' '||v2);
  else 
    for v_s in (select deptno,count(*) num from scott.emp group by deptno)
       loop
         dbms_output.put_line('删除记录后各个部门的部门号和人数为' ||v_s.deptno||' '||v_s.num);
       end loop;
  end if;
end t4;


delete from scott.emp where hiredate<=to_date('1980-12-17','yyyy-mm-dd');

注意:

对于oracle行级触发器(for each row),不能对本表做任何操作,即行级触发器中,不能查询和修改(DML)自身表 。否则会触发 ORA-04091 关于在oracle行级触发器中访问本表的错误

二、系统触发器(系统触发器在发生如数据库启动或关闭等系统事件时触发)
功能要求通过触发器记录是何用户,何时登陆了系统。

//先创建用户活动表
create table u1
(username varchar2(10),
activity varchar2(10),
time date);

//创建登录触发器
create or replace trigger t5
  after logon on database
begin
 insert into u1 values(user,'LOGON',sysdate);
end t5;

//调用
select  username,activity,to_char(time,'yyyy-mm-dd hh24:mi') from u1;

通过触发器记录是何用户,何时退出了系统。

用户表和上面的一样即可

create or replace trigger t6
  before logoff on database
begin
 insert into u1 values(user,'退出',sysdate);
end t6;


select  username,activity,to_char(time,'yyyy-mm-dd hh24:mi') from u1;

三、触发器提升

(1)通过触发器禁止用户的某项操作

功能要求:建一触发器,作用为禁止在星期四改变scott.emp雇员信息(包括添加删除和修改)。

预备知识:

①日期型转化为字符串型
Select to_char(sysdate,'yyyy-MM-dd HH24:mi')  from dual;

通常用户自定义异常是在声明后才能产生,但raise_application_error函数就可以直接产生异常。

 语法: raise_application_error(错误号,错误信息);

错误号和值在-20000-20999之间,错误信息的文本长度最大不能超过512个字

函数作用:将应用程序专有的错误从服务器端转达到客户端应用程序,并禁止用户的该项操作

create or replace trigger t7
   before insert or update or delete on scott.emp
begin
  if to_char(sysdate, 'DAY') in ('星期四') then
    raise_application_error(-20001,'不能在星期四修改员工信息');
  end if;
end t7;

update scott.emp set ename='candy'  where empno=7876;

(2)注意: 权限问题和变异表问题

创建一个触发器,在修改dept表的部门号后,同时更新emp表中相应的员工的部门号。

(主键动,外键从。修改dept表的部门号后,emp表的员工部门号会自动更改)

create or replace trigger tr
after update of deptno on scott.dept
   for each row
begin
  update scott.emp  set deptno=:new.deptno
    where deptno=:old.deptno;
end  tr;

 注意:必须先删掉system用户下所有的trigger,然后切换到Scott用户创建触发器才可以。

(3) 补充---变异表的解决方案

Oracle变异表ORA-04091错误的解决方案

针对scott.emp表为了实现在更新员工所在部门时,该部门中员工人数不超过8人,请建立一个触发器。
(为了实现在更新员工所在部门或向部门插入新员工时,部门中员工人数不超过8人,可以在emp表上创建两个触发器,同时创建一个共享信息的包。 )

解决方案:

n一个package,用来共享变量

n一个for each row  触发器,用来给共享变量赋值

n一个语句级触发器,用来做计算或者统计。

//创建包
create or replace package pp
as
 v_deptno scott.dept.deptno%type; 
end pp ;  

//触发器1
create or replace trigger t1
  before insert or update of deptno on scott.emp for each row
begin
   pp.v_deptno:=:new.deptno;
end t1;

//触发器2
create or replace trigger t2
    after insert or update of deptno on scott.emp
declare
  v_num number(3);
begin
  select count(*) into v_num from scott.emp 
         where deptno=pp.v_deptno;
  if v_num>2 then
     raise_application_error(-20003,'too many employees in department'||pp.v_deptno);
  end if;
end t2;

//调用
insert into scott.emp(empno,ename,sal,deptno) values(2,'WANG',2000,10);

 

你可能感兴趣的:(触发器)