Oracle学习笔记之触发器
触发器
触发器(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学习笔记之触发器的更多相关文章
- Oracle 学习笔记 19 -- 触发器和包浅析(PL/SQL)
		
触发器是存放在数据库中的一种特殊类型的子程序.不能被用户直接调用,而是当特定事件或操作发生时由系统自己主动 调用执行.触发器不能接受參数.所以执行触发器就叫做触发或点火.Oracle事件指的是数据库的 ...
 - oracle 学习笔记之触发器
		
说明 数据库触发器是一个与表相关联的.存储的PL/SQL程序. 每当一个特定的数据操作语句(Insert,update,delete)在指定的表上发出时,Oracle自己主动地运行触发器中定义的语句序 ...
 - Oracle学习笔记十三 触发器
		
简介 触发器是当特定事件出现时自动执行的存储过程,特定事件可以是执行更新的DML语句和DDL语句,触发器不能被显式调用. 触发器的功能: 1.自动生成数据 2.自定义复杂的安全权限 3.提供审计和 ...
 - Oracle学习笔记—数据字典和常用命令(转载)
		
转载自: oracle常用数据字典和SQL语句总结 Oracle常用命令大全(很有用,做笔记) 一.Oracle数据字典 数据字典是Oracle存放有关数据库信息的地方,其用途是用来描述数据的.比如一 ...
 - Oracle学习笔记三 SQL命令
		
SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)
 - oracle学习笔记第一天
		
oracle学习笔记第一天 --oracle学习的第一天 --一.几个基础的关键字 1.select select (挑选) 挑选出显示的--列--(可以多列,用“,”隔开,*表示所有列),为一条 ...
 - Oracle学习笔记——点滴汇总
		
Oracle学习笔记——点滴汇总 http://www.botangdb.com/ Oracle GI = Grid Infrastructure = ASM + Cluster
 - Oracle学习笔记之四sp1,Oracle 11g的常用函数
		
从Oracle学习笔记之四,SQL语言入门中摘出来的,独立成一章节 3.1 字符类函数 ASCII(c)和CHR(i) 分别用于返回一个字符的ASCII码和返回给定ASCII值所对应的字符. C ...
 - Oracle学习笔记之四,SQL语言入门
		
1. SQL语言概述 1.1 SQL语言特点 集合性,SQL可以的高层的数据结构上进行工作,工作时不是单条地处理记录,而对数据进行成组的处理. 统一性,操作任务主要包括:查询数据:插入.修改和删除数据 ...
 
随机推荐
- C#socket编程之实现一个简单的TCP通信
			
TCP(TransmissionControl Protocol)传输控制协议. 是一种可靠的.面向连接的协议(eg:打电话).传输效率低全双工通信(发送缓存&接收缓存).面向字节流.使用TC ...
 - idea Debug快捷键
			
快捷键 介绍 F7 在 Debug 模式下,进入下一步,如果当前行断点是一个方法,则进入当前方法体内, 如果该方法体还有方法,则不会进入该内嵌的方法中 * F8 在 Debug 模式下,进入下一步,如 ...
 - android studio出现offline情况
			
1.检查是否打开开发者选项 2.检查手机是否处于传输文件模式
 - layer结合art实现弹出功能
			
模板 <!-- 模板 --> <script id="render-tpl" type="text/html"> <table c ...
 - SQL 函数 coalesce()、row_number()的用法
			
coalesce()函数 ①用途: 将空值替换成其他值 返回第一个非空值 ②表达式: COALESCE是一个函数, (expression_1, expression_2, ...,expressio ...
 - photoKit使用笔记
			
@主要用到的类 1PHAssetCollection:图片资源数组(代表着相簿数组) 作用:获取相簿资源数组 示例代码: //获取相簿资源 PHFetchResult<PHAssetCollec ...
 - angular 引入编辑器遇到的各种问题。。。
			
1.项目中找不到angular-cli.json,也找不到angular.json 2. 3.
 - ajax 提交数组 泛型集合
			
ajax 提交数组 泛型集合 发表于2015/12/31 14:26:29 5117人阅读 分类: mvc asp.net webapi ORM 转载:http://blog.csdn.net/li ...
 - react 的基础
			
首先下载React 的安装包,可以到官网下载.也可以使用React Demos 已经自带 React 源码,不用另外安装,只需把这个库拷贝到硬盘中使用. (可参考http://www.ruanyife ...
 - centos7版本中ssh相关的设置
			
1.设置SSH连接端口1.1.关闭SELinux--关闭系统当前selinux# setenforce 0 --关闭系统永久selinux# sed -i 's/SELINUX=enforcing/S ...