触发器

触发器(trigger)是一些过程,与表关系密切,用于保护表中的数据,当一个基表被修改(INSERT、UPDATE或DELETE)时,触发器自动执行,例如通过触发器可实现多个表间数据的一致性和完整性。触发器和应用程序无关。

触发器的类型有三种:

(1)DML触发器。Oracle可以在DML(数据操纵语句)语句进行触发,可以在DML操作前或操作后进行触发,并且可以在每个行或该语句操作上进行触发。

(2)替代触发器。由于在Oracle中不能直接对有两个以上的表建立的视图进行操作,所以给出了替代触发器。它是Oracle专门为进行视图操作的一种处理方法。

(3)系统触发器。在Oracle8i时,提供了第三种类型的触发器叫系统触发器。它可以在Oracle数据库系统的时间中进行触发,如Oracle数据库的关闭或打开等。

创建触发器有以下限制:

(1)代码大小。触发器代码大小必须小于32K。

(2)触发器中有效语句可以包括DML语句,但不能包括DDL语句。ROLLBACK、COMMIT、SAVEPOINT也不能使用。

(3)LONG、LONG RAW和LOB的限制:

①   不能插入数据到LONG或LONG RAW;

②   来自LONG或LONG RAW的数据可以转换成字符型(如char、varchar2),但是不能超过32K;

③   使用LONG或LONG RAW不能声明变量;

④   在LONG或LONG RAW列中不能使用:NEW和:PARENT;

⑤   在LOB中的:NEW变量不能修改。

每张基表最多可

建立12个触发器,它们是:

(1)   BEFORE INSERT;

(2)   BEFORE INSERT FOR EACH ROW;

(3)   AFTER INSERT;

(4)   AFTER INSERT FOR EACH ROW;

(5)   BEFORE UPDATE;

(6)   BEFORE UPDATE FOR EACH ROW;

(7)   AFTER UPDATE;

(8)   AFTER UPDATE FOR EACH ROW;

(9)   BEFORE DELETE;

(10) BEFORE DELETE FOR EACH ROW;

(11) AFTER DELETE;

(12) AFTER DELETE FOR EACH ROW。

例如:做一个触发器,当删除dept表中部门时,将emp表中该部门人员信息清空;

createorreplacetrigger emp_dept

  afterdelete  on   dept

  foreachrow

declare

  

begin

deletefrom emp where emp.deptno=:old.deptno;

--表示删除或者修改前该记录旧的数据;

end emp_dept;

例如:修改上题,要求将删除的dept和emp表数据备份到指定表 deptOld和empOld表结构和dept、emp结构一致;

createorreplacetrigger emp_dept

  afterdelete  on   dept

  foreachrow

declare

   cursor cur isselect*from emp where emp.deptno=:old.deptno;

   e emp%rowtype;

   department dept%rowtype;

  

begin

    deletefrom emp where emp.deptno=:old.deptno;

    ifsql%foundthen

       open cur;

       loop

            fetch 
cur
into e;

              insertinto empOld values(e.empno,e.ename,e.job,e.job,e.mgr,e.hiredate,e.sal,e.comm,e.deptno);

         exitwhen cur%notfound;

       endloop;

    endif;

           insertinto deptOld values(:old.deptno,:old.dname,:old.loc);

end emp_dept;

 

create or replace trigger deleteDeptTrigger

after delete on dept

for each row

declare

type cur_type is ref cursor;

cur cur_type;

emp_row emp%rowtype;

begin

open cur for

select * from emp where deptno=:old.deptno;

delete from emp where deptno=:old.deptno;

loop

fetch cur into emp_row;

exit when cur%notfound;

insert into empOld values(emp_row.empno,emp_row.ename,emp_row.job,emp_row.mgr,emp_row.hiredate,emp_row.sal,emp_row.comm,emp_row.deptno);

end loop;

close cur;

insert into deptOld values(:old.deptno,:old.dname,:old.loc);

end
deleteDeptTrigger;

305讲解内容:

create or replace trigger deptTrigger

after delete on dept

for each row

declare

dept_deptno number(5);

type cur is ref cursor return emp%rowtype;

empcur cur;

emprow emp%rowtype;

begin

dept_deptno:=:old.deptno;

open empcur for select * from emp where emp.deptno=dept_deptno;

delete from emp where deptno=dept_deptno;

loop

fetch empcur into emprow;

insert into oldemp values(e.nextval,emprow.empno,emprow.ename,emprow.job,emprow.mgr,emprow.hiredate,emprow.sal,emprow.comm,emprow.deptno);

exit when empcur%notfound;

end loop;

end
deptTrigger;

创建替代(Instead_of)触发器:

Instead_of用于对视图的DML触发。由于视图有可能由多个表进行关联(Join)而成,因

而并非所有的关联都是可更新的。但是可以按如下例子来创建触发器。

例如:

在scott数据库中创建视图和触发器,以说明替代触发器。

      CREATEORREPLACE VIEW emp_avgSalView

    
AS   SELECT deptno,AVG(sal)   AS   avgSAL    FROM  emp

     GROUPby deptno;

创建该视图的替代触发器:

       CREATETRIGGER empAvgSalDel

   
INSTEADOFDELETEON  
emp_avgSalView 
FOREACHROW

  BEGIN

   
DELETEFROM  emp  WHERE  deptno=:OLD.deptno;

  END
cs_kc_avg_del
;

 

创建系统触发器:

Oracle8i开始提供的系统触发器可以在DDL或数据库系统上被触发。

DDL指的是数据定义语句,如CREATE、ALTER和DROP等。而数据

库系统事件包括数据库服务器的启动或关闭,用户登录与退出等。

--创建当一个用户userA登录时自动记录一些信息的触发器。

  CREATETRIGGER loguserAconnects

    AFTER LOGON ONSCHEMA

  BEGIN

    INSERTINTO LOGIN VALUES(‘userA’,’loguserAconnects fired’);

  END loguserAconnects;

 

面试题笔试题查询:

1、通过case when行编列,列边行;

2、删除重复行、留重复行中的一行记录。

3、Nvl和nvl2 区别

4、说出常用的10个数据库函数

5、索引如何使用? 何时失效?

6、Sql语句级别的优化?

7、函数和存储过程区别?

8、手写存储过程。

9、Oracle分页语句和mysql分页语句?

10、Rowid什么是事务?

例如:查询2000-3000之间的sal和、 4000-6000之间sal和、6000-8000sal和、

Select  sum(

Case when
sal between 2000 and 3000

Then sal
else 0 end

) ,sum(

 Case when sal between 4000and 6000

Then sal
else 0 end

) from emp

Select  count(

Case when sal between 2000 and 3000

Then empno else null end

) ,count(

Case when sal between 4000and 6000

Then empno else null end

) from
emp

 

综合实例:

模拟银行汇款、取款、以及存款、余额查询操作:

Id、卡号、密码、存款余额

create table
bankMsg( id number(15) primary key,cardno
varchar2(20) unique not null,pwd
varchar2(20) not null,

money number(15,2)

);

Id、卡号、操作标示符(A存款、B取款、C转账)、操作时间、操作金额

create table
bankMsgHistory(id number(5) primary key,cardno
varchar2(20),

flag varchar2(1),markDate
date,money number(15,2)

)

 

写一个函数验证是否登陆成功;

写一个存储过程、用于操作存款、取款、转账以及余额查询;

(注意:由于触发器获取不到操作标示符因此不写这个触发器了)写一个触发器,当bankMsg表被修改以后,触发操作记录表数据新增;

登陆操作函数:

create or replace function bankLoginByCardno(cardno_param in varchar2,pwd_param in varchar2) return number is

total number(5);

flag number(1):=0;

begin

select count(*) into total from bankMsg where cardno =cardno_param and pwd=pwd_param;

if total >0 then

flag:=1;

end if ;

return flag;

end
bankLoginByCardno;

存储过程:

--该存储过程,根据用户名密码登陆, 卡号为用户名,pwd自定义,

--根据操作标示Flag (A存款、B取款、C转账) 对银行卡信息数据进行修改,
然后触发记录表记录操作记录

/*

 username :用户名

 pwd:密码

 controlFlag操作标示符

 money金额

 targetCardno对方卡号

 succssOrError 是否操作成功,1 成功,0 失败

 errorMsg 操作失败原因out类型参数

 showMsg 查询余额信息的out类型变量

*/

create or replace procedure userBankCardnoMsg(username in varchar2, pwd in varchar2,

controlFlag in varchar2,money_param in number,targetCardno in varchar2,successOrError out number,

errorMsg out varchar2,

showMsg out bankMsg%rowType

) is

flag number(5):=0;

flag2 number(5):=0;

money number(15,2);

begin

successOrError:=0;--成功失败标示符默认为0

flag:=bankloginbycardno(username,pwd);

--
money_param:=nvl(money_param,0);

if flag=1 then--登陆成功

select money into money from bankMsg where cardno=username;

case controlFlag

when 'A' then--存款

update bankMsg set money=money+money_param    where cardno=username;--修改金额

insert into bankMsgHistory values(bankcardno_seq.nextval,username,controlFlag,sysdate,money_param);

successOrError:=1;

errorMsg:='存款成功';

select * into showMsg from bankMsg where cardno=username;

when 'B' then--取款

if money>=money_param then--判断是否有足够余额

update bankMsg set money=money-money_param    where cardno=username;--修改金额

insert into bankMsgHistory values(bankcardno_seq.nextval,username,controlFlag,sysdate,money_param);

successOrError:=1;

errorMsg:='取款成功';

select * into showMsg from bankMsg where cardno=username;

else

successOrError:=0;

errorMsg:='取款失败,余额不足';

end if;

when 'C' then--转账

select count(*) into flag2 from bankMsg where 
cardno=targetCardno;--查看目标账号是否存在

if flag2<=0 then

successOrError:=0;

errorMsg:='转账失败,目标卡号不存在';

else

if money>=money_param then--判断是否有足够余额

update bankMsg set money=money-money_param    where cardno=username;--修改金额

insert into bankMsgHistory values(bankcardno_seq.nextval,username,controlFlag,sysdate,money_param);

update bankMsg set money=money+money_param where cardno=targetCardno;--修改目标账号金额

insert into bankMsgHistory values(bankcardno_seq.nextval,targetCardno,'A',sysdate,money_param);

successOrError:=1;

errorMsg:='转账成功';

select * into showMsg from bankMsg where cardno=username;

else

successOrError:=0;

errorMsg:='转账失败,余额不足';

end if;

end if;

when 'D' then --查看余额

select * into showMsg from bankMsg where cardno=username;

successOrError:=1;

errorMsg:='查询操作成功';

else

successOrError:=0;

errorMsg:='操作失败';

end case;

else

successOrError:=0;

errorMsg:='登陆失败';

end if;

end userBankCardnoMsg;

测试代码:

-- Created on 2017/10/23 by ADMINISTRATOR

declare

successFlag number(1);

errorMsg varchar2(50);

showMsg 
bankMsg%rowType;

begin

-- Test statements here

/*

   --测试存款

  
userBankCardnoMsg('111111','123','A',10,null,successFlag,errorMsg,showMsg);

 if successFlag=1
then

   
dbms_output.put_line(errorMsg);

   
dbms_output.put_line('
卡号:'||showMsg.Cardno||'余额'||showMsg.Money);

  else

   
dbms_output.put_line(errorMsg);

  end if;

  */

/*--测试取款

  
userBankCardnoMsg('111111','123','B',10,null,successFlag,errorMsg,showMsg);

 if successFlag=1
then

   
dbms_output.put_line(errorMsg);

   
dbms_output.put_line('
卡号:'||showMsg.Cardno||'余额'||showMsg.Money);

  else

   
dbms_output.put_line(errorMsg);

  end if;

  */

/*--测试转账

  
userBankCardnoMsg('123321','123','C',10,'12321',successFlag,errorMsg,showMsg);

 if successFlag=1
then

    dbms_output.put_line(errorMsg);

   
dbms_output.put_line('
卡号:'||showMsg.Cardno||'余额'||showMsg.Money);

  else

   
dbms_output.put_line(errorMsg);

  end if;

  */

--测试查询余额

userBankCardnoMsg('222222','123','D',0,null,successFlag,errorMsg,showMsg);

if successFlag=1 then

dbms_output.put_line(errorMsg);

dbms_output.put_line('卡号:'||showMsg.Cardno||'余额'||showMsg.Money);

else

dbms_output.put_line(errorMsg);

end if;

end;

 

 

--------------------例子-----------------------------

存储过程:

create or replace procedure
Test_emp(username in varchar2,pwd
in varchar2,
flag in varchar2,res
out p_1.cur_type,msg
out varchar2 )

is f boolean;

begin

f:=test_login(username,pwd);

if f
then--验证通过

case when
flag='1' then--查询所有数据

open
res for select * from
emp;

msg:='查询所有记录成功';

when
flag='2' then--查询当前数据

open
res for select * from
emp where emp.ename=username
and emp.empno=pwd;

msg:='查询当前记录成功';

when
flag='3' then--清空emp表

delete from
emp;

msg:='截断表成功';

end case;

else

msg:='验证不通过';

end if;

end Test_emp;

----自定义函数:

create or replace function
Test_login(username in varchar2,pwd
in varchar2) return boolean is

Result boolean  ;

total integer;

begin

select count(*) into
total from emp where
emp.ename=username and
emp.empno=pwd;

if
total>0 then

return true;

else

return false;

end if;

end Test_login;

-------测试----------

-- Created on 2015/3/24 by
ADMINISTRATOR

declare

res p_1.cur_type;

msg varchar2(200);

flag varchar2(1):='3';

r emp%rowtype;

begin

test_emp('SMITH','7369',flag,res,msg);

dbms_output.put_line(msg);

if
flag='1' then

loop

fetch
res into r;

exit when
res%notfound;

dbms_output.put_line(r.empno||r.ename||r.hiredate);

end loop;

elsif
flag='2' then

loop

fetch
res into r;

exit when
res%notfound;

dbms_output.put_line(r.empno||r.ename||r.hiredate);

end loop;

elsif
flag='3' then

null;

end if;

exception when others then null;

end;

Oracle学习笔记之触发器的更多相关文章

  1. Oracle 学习笔记 19 -- 触发器和包浅析(PL/SQL)

    触发器是存放在数据库中的一种特殊类型的子程序.不能被用户直接调用,而是当特定事件或操作发生时由系统自己主动 调用执行.触发器不能接受參数.所以执行触发器就叫做触发或点火.Oracle事件指的是数据库的 ...

  2. oracle 学习笔记之触发器

    说明 数据库触发器是一个与表相关联的.存储的PL/SQL程序. 每当一个特定的数据操作语句(Insert,update,delete)在指定的表上发出时,Oracle自己主动地运行触发器中定义的语句序 ...

  3. Oracle学习笔记十三 触发器

    简介 触发器是当特定事件出现时自动执行的存储过程,特定事件可以是执行更新的DML语句和DDL语句,触发器不能被显式调用.   触发器的功能: 1.自动生成数据 2.自定义复杂的安全权限 3.提供审计和 ...

  4. Oracle学习笔记—数据字典和常用命令(转载)

    转载自: oracle常用数据字典和SQL语句总结 Oracle常用命令大全(很有用,做笔记) 一.Oracle数据字典 数据字典是Oracle存放有关数据库信息的地方,其用途是用来描述数据的.比如一 ...

  5. Oracle学习笔记三 SQL命令

    SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)  

  6. oracle学习笔记第一天

    oracle学习笔记第一天 --oracle学习的第一天 --一.几个基础的关键字   1.select select (挑选) 挑选出显示的--列--(可以多列,用“,”隔开,*表示所有列),为一条 ...

  7. Oracle学习笔记——点滴汇总

    Oracle学习笔记——点滴汇总 http://www.botangdb.com/ Oracle GI = Grid Infrastructure = ASM + Cluster

  8. Oracle学习笔记之四sp1,Oracle 11g的常用函数

    从Oracle学习笔记之四,SQL语言入门中摘出来的,独立成一章节 3.1 字符类函数 ASCII(c)和CHR(i)    分别用于返回一个字符的ASCII码和返回给定ASCII值所对应的字符. C ...

  9. Oracle学习笔记之四,SQL语言入门

    1. SQL语言概述 1.1 SQL语言特点 集合性,SQL可以的高层的数据结构上进行工作,工作时不是单条地处理记录,而对数据进行成组的处理. 统一性,操作任务主要包括:查询数据:插入.修改和删除数据 ...

随机推荐

  1. Unity日常记录 - QualitySettings 性能设置

    unity打包时,可通过QualitySettings优化图像性能,这是最常设置也是最明显的图像性能体现 设置图形质量的水平,一般来说,质量是以牺牲性能为代价的,所以最好不要追求移动设备或旧硬件的最高 ...

  2. python+selenium测试

    网址http://blog.csdn.net/u011541946/article/category/6788788/1

  3. Day 4 变量常量

    编辑语言的分类 编程语言,他是人与计算机沟通的一种介质 机器语言 计算机只认识0和1,为了和计算机沟通,你也得认识0和1 优点:执行效率快 缺点:普通人根本就写不了这种代码,开发效率低 汇编语言 他还 ...

  4. Monkey工具

    Android自动化测试方法,对其中的一些工具.方法和框架做了一些简单的整理,其中包括android测试框架.CTS.Monkey. Monkeyrunner.benchmark.其它test too ...

  5. 处女座与复读机 DP

    题目链接:https://ac.nowcoder.com/acm/contest/327/G 题意:给你两个字符串序列,让你根据第二个序列判断是不是 复读机,复读机会有以下特征 1.       将任 ...

  6. Android中控件之间添加分割线

    将以下view标签放置在需要分割的两个控件之间: <View android:layout_width=”match_parent” android:layout_height=”1dp” an ...

  7. vue keep-alive 取消某个页面缓存问题

    keep-alive keep-alive是Vue提供的一个抽象组件,用来对组件进行缓存,从而节省性能,由于是一个抽象组件,所以在v页面渲染完毕后不会被渲染成一个DOM元素 <keep-aliv ...

  8. PAT 1120 Friend Numbers

    1120 Friend Numbers (20 分)   Two integers are called "friend numbers" if they share the sa ...

  9. Mongoose 'static' methods vs. 'instance' methods

    statics are the methods defined on the Model. methods are defined on the document (instance). We may ...

  10. MHA实现MySQL的高可用

    一:软件简介 MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件. 在 ...