pl/sql
1、什么是pl/sql
pl/sql就是对sql语言的拓展,在之前所学的sql基础上又添加了一些编程语言的特性。所以pl/sql是把数据操作和查询组织在过程化单元里面,通过逻辑判断、循环等实现复杂的功能或者计算。
例子:对员工表涨工资。ios工种涨500,Android涨300,其余涨1000。
例子:通过每个人的身份证号知道每个人的生日。
2、为什么要学习pl/sql
1、可以更高效地操作数据库
2、想学习后面的触发器、过程、函数,pl/sql是基础
3、pl/sql怎样去学习
3.1、pl/sql的基本语法
declare
--说明部分(定义变量,若没有说明部分,那么declare可以不写。)
begin
--执行部分
end;
/
--执行结束
--案例1:通过pl/sql输出helloword
declare
begin
--执行部分
dbms_output.put_line('HelloWorld');
expection
--处理例外
end;
/
3.2、pl/sql中的变量定义
1、基本变量
java:int a=10;
pl/sql:a number:= 1000;
-- 案例:适用基本数据类型
declare
pname varchar2(20);
pnumber number;
begin
pname:='李四';
pnumber:='1000';
dbms_output.put_line(pname||''||pnumber);
end;
/
2、引用型变量
举例:pname emp.ename%type;
说明:将emp表中的ename字段的数据类型作为ename的数据类型。
--案例:查询员工表中编号为1的员工的姓名和工资
declare
pname emp.ename%type;
psal emp.sal%type;
begin
select ename,sal into pname,psal from emp where empno=1;
--将查到的ename与sal放到pname与psal中
dbms_output.put_line(pname||'的工资是'||psal);
end;
/
3、记录型变量
举例:emp_res emp%rowtype
--新建一个变量emp_res 使其等于emp表的第一行数据类型
--案例:查询员工表中编号为1的员工的所有信息
declare
emp_res emp%rowtype;
begin
select * into emp_res from emp where empno=1;
dbms_output.put_line('编号为'||emp_res.empno||'的'||emp_res.ename||'工资是'||emp_res.sal||'工种是'||emp_res.job);
end;
/
3.3、pl/sql中的循环和if else
if else
1、if 条件 then 执行语句1,执行语句2,执行语句3,执行语句4;
end if;
2、if 条件1 then 执行语句;
else 执行语句;
end if;
3、if 条件1 then 执行语句;
elsif 条件2 then 执行语句;
elsif 条件3 then 执行语句;
else 执行语句;
end if;
--案例:让用户通过键盘录入数据
accept num prompt('请输入一个数字');
declare
pnumber number:=#
begin
if pnumber=1 then dbms_output.put_line('输入的数字是1');
elsif pnumber =2 then dbms_output.put_line('输入的数字是2');
else dbms_output.put_line('输入的是其他数字');
end if;
end;
/
循环:while
while 循环的条件 loop
循环体
end loop;
--案例:通过while循环打印数字1到10
declare
i number:=1;
begin
while i<=10 loop
dbms_output.put_line(i);
i:=i+1; --plsql中没有++与--
end loop;
end;
/
循环:for
for i in 1..10 loop --i的取值从1开始到10结束
循环体
end loop;
--案例:通过for循环打印数字1到10
begin
for i in 1..10 loop
dbms_output.put_line(i);
end loop;
end;
/
循环:loop
loop
exit when 退出条件;
循环体
end loop;
--案例:通过loop循环打印数字1到10
declare
i number :=1;
begin
loop exit when i>10;
dbms_output.put_line(i);
i:=i+1;
end loop;
end;
/
3.4、pl/sql中的游标(光标,cursor,结果集(ResultSet))就是个结果集;
定义:cursor 光标的名字;(注意对比基本数据类型的顺序)
光标的名字 is select * from emp;
fecth把指针指向的数据返回,并将指针指向下一条数据
--案例:查看员工表中所有员工的姓名和工资
declare
pname emp.ename%type;
psal emp.sal%type;
--定义一个光标
cursor cemp is select ename sal from emp;
begin
--开启光标
open cemp;
--对光标的取值
loop
--循环体
fetch cemp into pname,psal;
exit when cemp%notfound; --循环结束的条件:循环到没有下一条数据
dbms_output.put_line(pname||'工资是'||psal);
end loop;
--关闭游标
close cemp;
end;
/
案例:供员工涨工资,ios的工种涨500,android的工种涨1000,其余涨2000;
alter table briup_emp modify (sal number (7,2));
declare
pempno briup_emp.empno%type;
psal briup_emp.sal%type;
pjob briup_emp.job%type;
cursor cemp is select empno,job,sal from briup_emp;
begin
open cemp;
loop
fetch cemp into pempno,pjob,psal;
exit when cemp%notfound;
if pjob='ios' then update briup_emp set sal = psal+500 where empno=pempno;
elsif pjob='android' then update briup_emp set sal = psal+1000 where empno=pempno;
else update briup_emp set sal = psal+2000 where empno=pempno;
end if;
end loop;
--关闭游标
close cemp;
end;
/
commit;
3.5、pl/sql中的例外
oracle 中的例外即语法错误
预定义例外:
no_data_found(没有找到数据)
too_many_rows(匹配了多个行)
zero_divide(除数为0)
value_error(数据类型转换失败)
timeout_on_resource(资源连接超时)
案例:模拟no_data_found例外
declare
pname briup_emp.ename%type;
begin
select ename from briup_emp where empno=100;
expection ---例外处理情况
when no_data_found(错误名称) then dbms_output.put_line(‘没有找到这个员工’);(错误之后该怎么做)
when others then dbms_output.put_line('出现了其他情况');
end;
/
案例:模拟too_many_rows例外
declare
pname briup_emp.ename%type;
begin
select ename into pname from briup_emp where empno=1;
expection ---例外处理情况
when too_many_rows(错误名称) then dbms_output.put_line(‘匹配了多行数据’);(错误之后该怎么做)
when others then dbms_output.put_line('出现了其他情况');
end;
/
3.6、pl/sql中的过程(存储过程,没有返回值)
指存储在数据库中共所有用户调用的子程序
概念:过程是一种命名的pl/sql代码块,它既可以没有参数,也可以有参数,既可以有In参数,也可以有out参数,但他没有返回值。过程一旦被创建好,就会储存到数据库中,过程不能被普通的sql语句调用的,第一个调用方式通过execute或者在pl/sql代码块中调用,因为过程是提前编译好的代码,所以执行效率很高。
过程该如何创建(用法):
create [or replace] procedure_pro_name[(参数列表:参数名 参数类型(输入/输出参数) 数据类型)] is | as(说明部分)begin..........end;/
案例:通过过程打印helloword
create or replace procedure dbms_helloword
is
begin
dbms_output.put_line('helloword');
end;
/
调用:execute dbms_helloworld;
内部调用:begin
dbms_helloword;
dbms_helloword;
end;
/
案例:通过过程向员工表中添加一条数据
create or replace procedure insert_emp
is
begin
insert into birup_emp(ename) value('yxx');
--commit;不应该写在过程中,因为是否提交应该由调用者来处理。
end;
/
案例:向过程中添加输入参数(通过员工编号查询员工的名字)
create or replace procedure select_emp_by_empno(eno in number)
is
pname briup_emp.ename%type;
begin
select ename into pname from briup_emp where empno=eno;
dbms_output.put_line(enp||'员工名字为'||ename)
end;
/
内部调用:begin
select_emp_by_empno(2);
end;
/
案例:向过程中添加输出参数,好比过程抛出的结果(通过员工编号查询工种和工资)
create or replace procedure select_emp_by_empno
(eno in number,--通过这个输入参数指定查询的员工号
ejob out varchar2,
esal out number
)
is
pjob briup_emp.job%type;
psal briup_emp.sal%type;
begin
select job,sal into pjob,psal from briup_emp where empno=eno;
exception ---例外处理情况
when no_date_found then dbms_output.put_line('没有这个员工’);
when others then dbms_output.put_line('出现了其他情况');
end;
/
内部调用:
declare
pjob briup_emp.job%type;
psal briup_emp.sal%type;
begin
select_emp_by_empno(2,pjob,psal);
dbms_output.put_line('工种是'||pjob||'工资是'||psal)
end;
/
删除过程:drop procedure procedure_name
3.7、pl/sql中的函数(存储函数)
指存储在数据库中共所有用户调用的子程序
共同点:都是执行某个功能的代码块
不同点:是否有return返回值
概念:函数一般用于计算或者返回一个值,函数在创建的时候和过程很相似调用时完全不同,函数调用时需要表达式,pnmuber:=函数,函数必须有返回值。
create or relpace function fun_name(参数列表)
return 返回值类型
is/as
...................
--案例:计算一个员工的年工资
create or replace function years_salary(eno in number)
return number
is
pys number(10);
begin
select sal*12 into pys from briup_emp where empno=eno;
return pys;
end;
/
declare
pyear_sal number(10);
begin
pyear_sal:=year_salary(1);
dbms_output.put_line('年薪是'||pyear_sal);
删除函数:drop function fun_name;
3.8、通过pl/sql编写触发器
结合一些案例
概念
触发器是一个与表关联的pl/sql程序,insert update delete 会在指定的表上发出时,Oracle会在佛那个执行触发器中的相关逻辑。
作用
1、可以实现安全性检查,2、数据确认,3、审计功能,4、数据备份或同步
分类
语句级触发器:
行级触发器:
写法
create trigger tri_name
after | before insert | update | delete [of 字段名]
on table_name
[for each row 行级/不写的话为语句级]
......................
案例
案例1:第一个触发器(如果向员工表中新增了一个数据,那就在屏幕上打印一句“添加了一个员工”)
create trigger insert_briup_emp
after insert --插入成功后触发
on briup_emp
begin
dbms_output.put_line('添加了一个员工');
end;
/