在数据库的操作中,在编写sql语句的时候,我们可能会用到函数以及触发器等的操作来简化我们的工作。
在这片文章中,也和我以前的博文一样,不是纯粹的理论讲解,而是采用的是案例的方式进行笔记的记录说明。还是用到的以前博文中的员工表emp
1.认识plsql的函数
问题1 输入雇员姓名返回年薪
1 | create or replace function sp_func(spName varchar2) return number is |
总结:
语法:
create 【or replace】 function 函数名(参数1 类型1,参数2 类型2) return 返回值类型
is 变量、常量和游标的定义;
begin
执行部分
exception
异常处理部分(可选)
end;
调用函数的第一种方式
var income number; --定义全局变量var 变量名 变量类型
call sp_func('SCOTT') into:income; --全局变量赋值:call 函数into:全部变量名
print income; --打印全局变量 print 全局变量名
调用函数的第二种方式
select sp_func('SCOTT') from dual;
2,包
包:
主要是一种用来组织和管理过程和函数的一种机制,主要由两部分组成,包规范和包体
包里面主要是声明一下过程和函数,过程和函数的实现放在包体里面
–创建包:包里面只是声明过程和函数
问题:创建一个包,包含一个过程,包含一个函数,
过程:输入员工姓名,新的工资,更新员工工资。
函数:输入员工的姓名,计算该员工的收入
1 | createor replace package sp_package is |
总结
语法:创建包
1 | create 【or replace】 package 包名 is |
过程的实现放在包体里面,包里面只是声明过程和函数
–创建包体:
1 | create or replace package body sp_package is |
创建包体的语法
create 【or replace】 package body 包名 is
过程1实现体
过程2实现体
....
函数1实现体
函数2实现体
end;
包中的过程和函数的调用 通过 包名.过程名或者 包名.函数名 来调用的
1 | exec sp_package.update_sal('SCOTT',4500); |
PL/SQL变量:标量类型,复合类型,参照类型lob(large object)类型
–标量类型: 变量名【constan】 数据类型【not null】【:=值】|【default 值】;
案例:
定义一个变长的字符串:v_ename varchar2(20);
定义一个小数:v_vearsal number(7,2);
定义一个小数,给初始值为3.14:v_sal number(3,2):=3.14;
定义一个常量PI给默认值为3.14:PI constant number(3,2):=3.14;
定义一个日期类型;v_hiredate date
定义一个布尔类型 v_invid boolean not null default false;
编写一个PL/sql块,输入员工编号,显示雇员的姓名和工资,以及个人所得税(税率为0.05)
1 | declare |
%type :输入标量类型一种,比较灵活 v_ename emp.ename%type;表示v_ename 和emp表中的ename类型一样
复合类型:
(1)PL/SQL的记录类型:
(2)pl/sql的表类型
(3)嵌套表类型
(4)varray类型
(1)PL/SQL记录类型:%rowtype
1 | 案例:输入一个员工编号,显示该员工的所有信息 |
记录类型(自定义的)
1 | declare |
记录类型的语法:
type 类型名 is record(变量1 数据类型1 ,变量2 数据类型2,….)
变量名 类型名;
PL/SQL的表类型
--表类型(类似于高级语言中的数组)
--定义表类型时,不定义表的大小
--定义表类型时,需要指定表中的每个数据的类型
--表类型的下标可以为正,可以为负。
1 | declare |
参照类型:游标
案例:输入一个部门名称,显示该部门所有员工的姓名和工资
1 | declare |
--总结:
--(1)定义:type 类型名 is ref cursor: 表明sp_cursor 是一个游标类型
--(2)test_cursor sp_emp_cursor;定义一个游标变量test_cursor,是sp_emp_cursor类型
--(3)open test_cursor for 查询语句;
--(4)fetch 游标变量名into 变量1,变量2;
--(5)exit when test_cursor%notfound; 定义循环退出的条件
--(6)close test_cursor :游标使用完要关闭游标,关闭游标
写法2(建议使用这一种写法)
1 | declare |
/*
cursor 游标变量名is select 语句
open 游标变量
fetch 游标变量into 变量1,变量2,….
close 游标变量
*/
–写法3:用for循环使用游标
1 | declare |
–for循环会自动打开游标和关闭游标
触发器:
当用户登录、退出或者是对对象进行操作的时候,或者是进行ddl操作的时候,引起某个存储过程的执行,我们把这样一个隐含调用的存储过程称之为触发器
1)我们在开发中,可能会提出这样的问题:
–当用户登录的时候,我们希望能够自动记录用户的名字和登录的时间
–当用户在周四或非工作日对表进行修改的时候,不允许这样做。
–当用户去删除一条记录的时候,希望能够将删除记录自动的备份到另外一张表中
解决方法:触发器
触发器分类:
dml触发器(insert,update,delete),
ddl触发器,系统事件触发器(登录、退出等操作)
下面我们通过例子,来具体的讲解
案例1:创建一张my_emp表,给该表添加记录,提示“添加一条数据”
1 | --语句级的触发器:针对update,insert,select只触发一次操作 |
–执行3次
insert into my_emp values(101,'ellen')
–案例2:在my_emp表中,修改id为101的员工信息的时候,修改一次提示一次
–for each row表明这是一个行级触发器:修改一行,触发一次输出操作
1 | create or replace trigger tri2 |
–创建触发器的语法结构
/*
create [or replace] trigger trigger_name
{befor|after]} {insert|update|delete}
on table_name
[for each row]
[when condition]
begin
–触发的操作
end;
*/
–案例3:在删除my_emp表中的记录的时候,提示’删除一条记录’
1 | create or replace trigger tri3 |
–案例4:在删除my_emp表中的记录的时候,触发报错操作,不让删除
1 | create or replace trigger tri4 |
/*
raise_application_error是oracle给我们提供的存储过程,
可以传入两个参数,第一个参数是错误号,-20000–20999之间,
第二个参数是报错信息
*/
–案例5:为了禁止工作人员在周四删除my_emp表中的员工信息,创建一个触发器完成这个操作
1 | create or replace trigger tri5 |
–案例6:禁止工作人员在周四修改员工信息(insert update delete),不同操作报错信息不同
1 | create or replace trigger tri6 |
–当触发器中同时包含多个触发事件时,为了区分触发事件,可以使用三个条件:updating,deleting,inserting
–案例7:修改员工工资的时候,要求新工资必须比原来工资高,创建一个触发器来解决这个问题,输出新工资和老工资
1 | create or replace trigger tri7 |
–:new:update操作完成之后的列的值
–:old:update操作完成前的列的值
–案例8:编写一个触发器,当用户删除my_emp的记录的时候,自动将删除的id和name备份到另外一张表中
1 | create table my_emp_bak as select * from my_emp where 1=2; |
–禁用触发器
alter trigger trigger_name disable;
–启用触发器
alter trigger trigger_name enable;
–删除触发器
drop trigger trigger_name;
–编写一个触发器,控制员工的新工资不能低于原来的工资,但是也不能高于原来工资的20%
1 | create or replace trigger tri9 |
–作业:创建一张学生表stu(id,name,birthdate),编写一个触发器,要求是:如果学生年龄小于18岁,则不允许插入
–Oracle的系统触发器:主要是针对oracle的系统事件的一个触发器
–Oracle定义的常用的系统事件:
–ora_client_ip_address:返回客户端的ip
–ora_database_name:返回数据库名
–ora_login_user:返回登录用户名
–ora_sysevent:返回触发器的系统事件名
–ora_des_encrypted_password:返回加密后的密码
–案例:为了记录用户登录和退出的时间,可以建立登录和退出的触发器
create table log_table(username varchar2(10),logon_time date,logoff_time date,address varchar2(20));
–创建登录触发器
1 | create or replace trigger logon |
–创建退出触发器
1 | create or replace trigger logoff |
–系统触发器需要时系统管理员身份才能创建
–ddl触发器:
–编写一个触发器,可以记录用户所进行的ddl操作
1 | create table my_ddl_event(event varchar2(20),username varchar2(10),time date); |
–禁用一张表上所有的触发器:
alter table 表名 disable all triggers;
–激活一张表上所有的触发器:
alter table 表名 enable all triggers;