触发器

来源:互联网 发布:如何编辑淘宝营销短信 编辑:程序博客网 时间:2024/05/20 20:19


------------------------------------环境代码

create  table student
(stuid varchar2(10) not null,
stuname varchar2(10) not null,
sex char(2)
);

create table subject
(subjectid int,
subjectname varchar2(10)
);


create table score
(
stuid int,
subjectid int,
score int
);

 

insert into student values (1001, 'wind', '男');
insert into student values (1002, 'snow', '女');
insert into student values (1003, 'apple', '男');
insert into subject values (1, 'oracle');
insert into subject values (2, 'java');
insert into score values (1001, 1, 90);
insert into score values (1002, 2, 88);


---------------主体部分

一、触发器
1.触发器具有三个部分
(1).触发事件
(2).可选的触发器约束条件
(3).触发器动作

2.可以新建对应如下语句的触发器
(1).DML语句(insert、delete、update)
(2)DDL语句(create、alter、drop)
(3).数据库操作(servererror、logon、logoff、startup、shutdown)

3.可以创建触发器的对象:1.数据库表 2.数据库视图 3.用户模式 4.数据库实例

4.触发器类型
(1).DML触发器(包括行级触发器、语句级触发器)
(2).系统触发器
(3).替代触发器
(4).模式触发器

5.执行DML语句的顺序
(1).执行before语句级触发器(如果存在)
(2).对于受语句影响的每一行执行DML语句
(3).执行after语句触发器(如果存在)

6.两个特殊的值
:new 新产生的值
:old 原是的值

7.触发器中的谓语
(1). inserting
(2).updating
(3). deleting

 

二、新建DML语句

create or replace trigger schemaname.triggername
before | after |delete |update of 列名
on 表名
[for each row]
when 条件

----------------
----------------第一部分:before触发器---------------
---------------

--案例01:新建一个测试的行前触发器
create or replace trigger tr01
before insert on student
begin
  dbms_output.put_line('这个是行前触发器!');
end;


--案例02:新建一个测试的行后触发器
create or replace trigger tr02
after update on student  /*没有for each row说明是个表级别触发器*/
begin
  dbms_output.put_line('这个是表级update触发器!');
/*如果你一次更新的语句是几条只触发一次!*/
end;


--案例03:新建一个测试的行后触发器:行级触发器

/*行级触发器即每操作一行都会触发一次触发器*/
create or replace trigger tr02
after update on student
for each row  /* each row说明是个行级别触发器*/
begin
  dbms_output.put_line('这个是行级update触发器!');
/*操作一条语句就触发一次这个触发器!*/
end;

--案例04:新建一个使用属性:new的insert触发器
create or replace trigger tr01
before insert on student
for each row   --必须是行级触发器
begin
  dbms_output.put_line('这个是行前触发器!');
  dbms_output.put_line('new id:' || :new.stuid);
  dbms_output.put_line('student name:' || :new.stuname);
  dbms_output.put_line('student sex:'  || :new.sex);
end;


--案例05:新建一个使用属性:old的delete触发器
create or replace trigger tr01
before delete on student
for each row   --必须是行级触发器
begin
  dbms_output.put_line('这个是行前触发器!');
  dbms_output.put_line('old id:  ' ||:old.stuid);
  dbms_output.put_line('old name:  ' ||:old.stuname);
  dbms_output.put_line('old sex:  ' ||:old.sex);
end;


--案例06:新建一个使用属性:old的update触发器
create or replace trigger tr01
before update on student
for each row   --必须是行级触发器
begin
  dbms_output.put_line('这个是行前触发器!');
  dbms_output.put_line('old id:'  || :old.stuid);
  dbms_output.put_line('old name:'  || :old.stuname);
  dbms_output.put_line('old sex:'  || :old.sex);
dbms_output.put_line('new id:' || :new.stuid);
  dbms_output.put_line('new name:' || :new.stuname);
  dbms_output.put_line('new sex:' || :new.sex);
end;


--案例07:新建一个使用条件的触发器
create or replace trigger tr01
before delete on student
for each row   --必须是行级触发器
when (old.sex='男')  /*这里old前面不能使用冒号只有在主体部分才允许使用冒号*/
begin
  dbms_output.put_line('这个是行前触发器!');
  dbms_output.put_line('old id' ||:old.stuid);
  dbms_output.put_line('old name' ||:old.stuname);
  dbms_output.put_line('old sex' ||:old.sex);
end;

--案例08:新建一个混合触发器01
(1)新建一个表

create table deltable as select * from student where stuid='';

(2)新建一个混合触发器
create or replace trigger tr03
before insert or update or delete on student
for each row
begin
 if inserting then
                 insert into deltable values(:new.stuid, :new.stuname, :new.sex);
                end if;
 if deleting then
   insert into deltable values (:old.stuid, :old.stuname, :old.sex);
 end if;         
exception
 when others then
dbms_output.put_line('不可预知的错误!');
end;


--案例09:新建一个混合触发器02
(1)新建一个表

create table deltable as select * from student where stuid='';

create table updtable as select * from student where stuid='';

create table intable as select * from student where stuid='';

(2)新建一个混合触发器
create or replace trigger tr03
before insert or update or delete on student
for each row
begin
 if inserting then
                 insert into intable values(:new.stuid, :new.stuname, :new.sex);
                end if;
 if deleting then
   insert into deltable values (:old.stuid, :old.stuname, :old.sex);
 end if;     
 if updating then
                     insert into updtable values(:new.stuid, :new.stuname, :new.sex);
                     insert into updtable values (:old.stuid, :old.stuname, :old.sex);
 end if;
exception
 when others then
dbms_output.put_line('不可预知的错误!');
end;

 

--案例10:新建一个混合触发器03
(1)新建一个表

create table deltable as select * from student where stuid='';

create table updtable as select * from student where stuid='';

create table intable as select * from student where stuid='';

(2)新建一个混合触发器
create or replace trigger tr03
before insert or update or delete on student
for each row
begin
 if inserting then
                 insert into intable values(:new.stuid, :new.stuname, :new.sex);
                 dbms_output.put_line('数据插入成功!');
                end if;
 if deleting then
   insert into deltable values (:old.stuid, :old.stuname, :old.sex);
   dbms_output.put_line('数据删除成功!');
 end if;     
 if updating then
                     insert into updtable values(:new.stuid, :new.stuname, :new.sex);
                     insert into updtable values (:old.stuid, :old.stuname, :old.sex);
      dbms_output.put_line('数据更新成功!');
 end if;
exception
 when others then
dbms_output.put_line('不可预知的错误!');
end;


----------------------------
----------------------------第二部分:after触发器
-------------------------------

 


--案例11:新建一个after触发器

--下面是库存表
create table goodstore
(
goodsno int primary key, --库存商品编号
goodscount int  --库存商品数量
);

--下面是商品出库表
create table goodstoreout
(
goodsno int,
goodcount int,
goodoutdate date default sysdate
);

insert into goodstore values (1001, 100);
insert into goodstore values (1005, 200);
insert into goodstore values (1002, 300);
insert into goodstore values (1003, 500);
insert into goodstore values (1004, 600);

--编号为1001的商品出库20件
insert into goodstoreout values (1001, 20, default);

--查询出库表
select * from goodstoreout;

--查询库存表
select * from goodstore;  --发现1001数据量有减少

--定义触发器
create or replace trigger tr04
after insert on goodstoreout
for each row
begin
  update goodstore set goodscount=goodscount-:new.goodcount
  where goodsno=:new.goodsno;
  dbms_output.put_line('本次出库的商品编号:' ||:new.goodsno || '   ' || '出库的数量为:'   ||to_char(:new.goodcount));
end;

 


--案例12:替代触发器
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.测试

 


--案例13:变异表的演示
--1.新建表
create table emp_tab as select * from emp;

--2.新建一个触发器

create or replace trigger emp_count
after delete on emp_tab
for each row
declare
  n integer;
begin
  select count(*) into n from emp_tab;
  dbms_output.put_line('there are now' || n );
end;

 

--案例14:维护触发器
alter triger tr01 disable;
alter trigger tr01 enable;


-----------
----------第三部分:内置程序包
----------

--案例15:验证dbms_output设置选项
SQL>set serveroutput on
SQL> set serveroutput on
SQL> set serveroutput on size 5000


 declare
   str varchar2(20):='hello world!';
  begin
  dbms_output.put(str);  /*结果屏幕上不会显示任何东西,dbms_output.put不具备显示功能*/
  end;
 


 declare
  str varchar2(20):='hello world!';
  begin
  dbms_output.put(str);
  dbms_output.put_line('good');--具有显示功能
  end;
 
/*这里面由于有两次将变量值保存到缓存中,所以打印时将缓存里面所有的值显示出来*/


--案例16-02:演示DBMS_LOB使用

--01.新建表
create table downfilelist
(
id varchar(20) not null primary key,
name varchar(40) not null,  /*文件存放位置*/
filelocation bfile,  /*文件描述*/
description clob
);

--02.新建需要的目录
/*
新建目录格式:;
create or replace directory  目录名 as  ‘本地或网络共享路径名’;
*/

create or replace directory filedir as 'f:/downlist' ;
--或
create or replace directory filedir as '//servername/downlist' ;

--03.对表的中数据操作
-a.插入数据到表中,对bfile类型的字段使用bfilename函数
insert into downfilelist values ('00001', 'java入门', bfilename(upper('filedir'), 'java.zip'), '这是一本使你快速学会的java教材');

-b.更新lob
select description from downfilelist where id='00001';

update downfilelist set description ='这是一本使你快速学会oracle的书', filelocation=bfilename(upper('filedir'), 'oracle.zip')
where id='00001';

select id, name, description from downfilelist;  /*在sqlplus中需要这样写否则无法显示或则不能写:
select * from downfilelist;
*/


--案例16-02:演示DBMS_LOB使用:read

declare
tempdesc clob;
ireadcount int;
istart int;
soutputdesc varchar(100);
begin
  ireadcount:=5;
  istart:=1;
  select description into tempdesc from downfilelist where id='00001';
dbms_lob.read(tempdesc, ireadcount, istart, soutputdesc); /*从istart取值,取ireadcont个*/
dbms_output.put_line('前五个字符是:'||soutputdesc);
end;


--案例16-03:演示DBMS_LOB使用:getlength
/*统计字符串长度*/
declare
  tempclob clob;
  ilen int;
begin
select description into tempclob from downfilelist where id='00001';
ilen:=dbms_lob.getlength(tempclob);
dbms_output.put_line('描述的字段长度为:'||ilen);
exception
  when others then
   dbms_output.put_line(sqlcode || '  ' ||sqlerrm);
end;


--案例16-03:演示DBMS_LOB使用:write

declare
  tempdesc clob;
  icount int;
  istart int;
  snewvar  varchar2(30);
begin
  icount:=2;
  istart:=1;
  snewvar:='这是非常畅销的书';
  select description into tempdesc from downfilelist
   where id='00001' for update;
   /*修改大数据时可能速度很慢所以锁定以便提高速度*/
dbms_output.put_line('更改前::'||tempdesc);
dbms_output.put_line('从' ||istart || '开始的'||icount ||'个字符将被改写成:'||snewvar);
dbms_lob.write(tempdesc, icount, istart, snewvar);
commit;  /*修改完数据后需要解锁所以提交否则别的用户不能使用数据*/
end;

select * from downfilelist where id=00001;