pl/sql编程----触发器

触发器 (trigger)
触发器指隐含的执行的存储过程,既当特定事件出现时自动执行的存储过程。
当定义触发器时,必须要指定触发的事件和触发的操作,常用的触发事件包括insert,update,delete语句,而触发操作实际就是一个pl/sql块

触发器的功能:自动生成数据,
自定义复杂的安全权限,
提供审计和日志记录,
启用复杂的业务逻辑

触发器类型
模式(DDL)触发器,执行DDL语句时执行
数据库级触发器,在发生打开,关闭,登录,退出数据库等系统事件时执行
DML触发器(行级触发器:对影响的每个行执行一次
语句级触发器:无论受影响的行数是多少,只执行一次
instead of 触发器 :用于用户不能直接使用DML语句修改的视图

限制:触发器中不能使用控制语句(commit,rollback,savepoint)
由触发器所调用的过程或函数也不能使用控制语句
触发器中不能使用long,long raw类型

当触发器被触发时,要使用被插入,更新或删除的记录中的列值,有时要使用操作前,后列的值。
实现:
:new 修饰符访问操作完成后列的值
:old修饰符访问操作前完成前列的值

使用create trigger 命令创建
语法
create or replace trigger 名
after/before/instead of
insert/[or]update of column/[or]delete
on 表名
[for each row ] --行触发器,每触发一行时触发
[when (condition)]
pl/sql块

before类型触发器

 脚本:
     --删除表
        drop table book;
       --创建表book
        create table book (bid number,bname varchar2(50),bhouse varchar2(50),pinym varchar2(50));
        --插入数据
        insert into book(bid,bname,bhouse,pinym) values(1,'笑傲江湖','人民出版社','xajh');
        insert into book(bid,bname,bhouse,pinym) values(2,'钢铁是怎样炼成的','人民出版社','gtszylcd');
        insert into book(bid,bname,bhouse,pinym) values(3,'平凡的世界','人民出版社','pfdsj');
        commit;
        
案例:before类型
--创建触发器,在插入一条记录或者修改了bid这个字段的时候将pinym修改为大写
--注意,如果这里我们修改的不是bid这个字段,则不会触发触发器,如果需要,只需要将of bid去掉
create or replace trigger tri_01 
before insert or update of bid 
on book
for each row
  begin
    :new.pinym :=upper(:old.pinym);
    end;
--测试
update book set bid = 3 where bid = 3
案例:before类型,条件类型
--创建触发器,在插入一条记录或者修改了bid这个字段的时候如果改变的这条记录pinym的字符长度大于5,修改出版社名称
create or replace trigger tri_01 
before insert or update of bid 
on book
for each row
   when (length(new.pinym)>5)
   --此处new不需要在前面加冒号
  begin
    --:new.pinym :=upper(:old.pinym);
      :new.bhouse := '繁花似锦出版社';
    end;
--测试
insert into book(bid,bname,bhouse,pinym) values(4,'鲁宾逊漂流记','人民出版社','lbxplj');

after类型触发器

案例:after类型
--创建触发器,在删除一条记录的时候,将这条记录备份在另一张表中
脚本:
--创建表
create table bbook as select * from book where 1<0;
--创建触发器
create or replace trigger tri_02 
after delete on book
for each row
  begin
    insert into bbook(bid,bname,bhouse,pinym) values(:old.bid,:old.bname,:old.bhouse,:old.pinym);
    end;

触发器谓词:
oracle提供了三个参数,inserting,updateing,deleting,用于判断触发了哪些操作
inserting,updateing,deleting如果触发的语句为,inset,update,delete语句,则为true,否则为false
我们可以根据这在写日志,追踪
案例:

--创建日志表
create table test_log(myuser number(3),mytype varchar(20),mydate date );
--创建序列
create  sequence xul;
--需要用到序列来实现序号的自动递增
--创建触发器 
create or replace trigger test_1
after delete or update or insert
on book
declare
  v_type test_log.mytype%type;
begin
    if inserting then
      v_type := 'insert';
      dbms_output.put_line('记录成功插入,记录到日志');
      insert into test_log(myuser,mytype,mydate) values (xul.nextval,v_type,sysdate);
    elsif deleting then   v_type := 'delete';
        dbms_output.put_line('记录成功删除,记录到日志');
        insert into test_log(myuser,mytype,mydate) values (xul.nextval,v_type,sysdate);
    elsif updating then   v_type := 'update';
      dbms_output.put_line('记录成功修改,记录到日志');
      insert into test_log(myuser,mytype,mydate) values (xul.nextval,v_type,sysdate);
    end if;
end;

案例:统计book表,并且在book进行删除,更新,插入操作时可以同步更新
脚本:

--创建表book
        create table book (bid number,bname varchar2(50),bhouse varchar2(50),pinym varchar2(50));
        --插入数据
        insert into book(bid,bname,bhouse,pinym) values(1,'笑傲江湖','人民出版社','xajh');
        insert into book(bid,bname,bhouse,pinym) values(2,'钢铁是怎样炼成的','人民出版社','gtszylcd');
        insert into book(bid,bname,bhouse,pinym) values(3,'平凡的世界','人民出版社','pfdsj');
        commit;
--创建统计表
create table tongj as 
       select bhouse,count(*) sum from book group by bhouse
--创建触发器
--原理:在进行操作之后,触发器将原来的统计表数据删除,使用游标将新统计的数据插入到统计表中,来实现同步更新
create or replace trigger zd_tongj 
after insert or update or delete on book
declare
--使用游标来进行数据存储
--游标的作用是用来存储多行数据
cursor C0 is select bhouse,count(*) sum from book group by bhouse;
 begin 
   delete from tongj;
   for C1 in C0 loop
     dbms_output.put_line('出版社:'||C1.bhouse||'数量:'||C1.sum);
     insert into tongj(bhouse,sum)values(C1.bhouse,C1.sum);
     end loop;
      close C0;
     end;
    /*
    --另一种循环方法创建触发器
    create or replace trigger zd_tongj
after insert or update or delete on book
declare
cursor C0 is select bhouse,count(*) sum from book group by bhouse;
C2 tongj.bhouse%type;
C3 tongj.sum%TYPE;
 begin
   delete from tongj;
   open C0;
 loop
   FETCH C0 INTO C2, C3;
    exit when C0%notfound;
      dbms_output.put_line('出版社:'||C2||'数量:'||C3);
      insert into tongj(bhouse,sum)values(C2,C3);
  end loop; 
   close C0;
end;*/
    --测试     
    delete from book where bid = 3

instead of 触发器
它主要用在视图上,当视图涉及到多张表,或者有统计函数不能进行修改时,我们是不能进行修改的,如果要修改,就要使用instead of 触发器。否则修改会报错
脚本:

 --删除表
 drop table students purge;
 drop table chengjs purge;
 --创建表
 create table students(xueh varchar2(5),xingm varchar2(10),xingb varchar2(3),nianl number(3));
 create table chengjs(xueh varchar2(5),kec varchar2(10),chengj number(3));
 --测试数据
 insert into students(xueh,xingm,xingb,nianl) values ('1','张三','男',18);
 insert into students(xueh,xingm,xingb,nianl) values ('2','李四','男',17);
 insert into students(xueh,xingm,xingb,nianl) values ('3','王五','男',19);
 insert into students(xueh,xingm,xingb,nianl) values ('4','马六','男',18);
 insert into chengjs(xueh,kec ,chengj) values ('1','语文',123);
 insert into chengjs(xueh,kec ,chengj) values ('1','数学',143);
 insert into chengjs(xueh,kec ,chengj) values ('1','英语',133);
 insert into chengjs(xueh,kec ,chengj) values ('2','语文',63);
 insert into chengjs(xueh,kec ,chengj) values ('3','英语',12);
 commit;
 --创建视图
 create or replace view stu_cheng_view
 as
 select s.xueh,s.xingm,c.kec,c.chengj
 from students s,chengjs c
 where s.xueh = c.xueh ;
 --命令行查看表结构:desc stu_cheng_view

如果在stu_cheng_view这个视图里面插入记录:

 insert into stu_cheng_view values('4','马六','数学',128);
   sql>ORA-01779: 无法修改与非键值保存表对应的列
   --因为视图是虚拟表,由两个表合成的,所以无法修改

但是如果想要修改,就必须使用instead of触发器

 create or replace trigger view_trigger
 instead of insert
 on stu_cheng_view
 for each row
 declare
 	cursor stu_cur is select * from students s where s.xueh = :new.xueh;
 	cursor cheng_cur is select * from chengjs c where c.xueh = :new.xueh and c.kec = :new.kec;
 	a stu_cur%rowtype;
 	b cheng_cur%rowtype;
 	begin
 	open stu_cur;
 	open cheng_cur;
 	fetch stu_cur into a;
    fetch cheng_cur into b; 
 	if stu_cur%notfound then
 	     insert into students(xueh,xingm,xingb,nianl) values (:new.xueh,:new.xingm,null,null);
 	else
 	     update students set xingm = :new.xingm where xueh = :new.xueh;
 	end if;
 	if cheng_cur%notfound then
 		  insert into chengjs(xueh,kec ,chengj) values (:new.xueh,:new.kec,:new.chengj);
 	else
 		    update chengjs set chengj = :new.chengj where xueh = :new.xueh and kec = :new.kec;
 	end if;
 	close stu_cur;
 	close cheng_cur;
 end;

DDL触发器(模式触发器):
适用于我们在创建,删除,,等DDL操作时,记录下我们的操作;
语法:

CREATE [OR REPLACE] TRIGGER trigger name {BEFORE | AFTER } { DDL
event} ON {DATABASE | SCHEMA} 范围是on database、on schema , on schema
作用范围只是在hr用户下create table等触发,其他用户则不会。若是on database则其他用户create table时会触发该触发器

案例:

--创建日志表
create table table_log(myuser varchar2(15),
mydate varchar2(20),
user_type varchar2(10),
obj_name varchar2(15),
obj_type varchar2(10) );
--创建触发器
create or replace trigger trr_log_table after drop or create on schema 
begin 
insert  into table_log values (user,sysdate,sys.dictionary_obj_name,sys.dictionary_obj_owner,sys.dictionary_obj_type);
end;

创建完成之后,在执行其他DDL操作,我们的操作记录就会留在table_log 这个表中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值