PL/SQL基础
PL/SQL操作oracle数据库效率最高,是学习存储过程,存储函数,触发器的前提。打印hello world:
1 | SQL> declare |
一、PL/SQL概念
PL/SQL(procedure language/sql)是oracle对sql语言的过程化扩展
SQL语言:数据操纵
过程语言:数据处理
组成pl/sql:简单、高效、灵活、实用
不同的数据库对sql的扩展
oracle :pl/sql
DB2:sql/pl
SQL Server:Transac_SQL(T-SQL)
二、PL/SQL基础语法
1 | SQL> declare |
1. 变量定义
定义基本变量
1
2
3
4
5
6--类型
char, varchar2, date, number, boolean, long
--例:
varl char(15);
married boolean := true;
psal number(7,2);引用型变量
1
2--例:
my_name emp.ename % type;记录型变量
可以理解为是个数组,数组中的每个元素为列
1
2
3
4--例:
emp_rec emp % rowtype;--行类型
--记录型变量的引用
emp_rec.ename := 'ADAMS';例子
查询并打印7839的姓名和薪水
1
2
3
4
5
6
7
8
9
10
11
12
13--定义引用型变量
SQL> declare
--pename varchar2(20); --基本变量
--psal number; --基本变量
pename emp.ename % type;
psal emp.sal % type;
begin
--得到7839的姓名和薪水
select ename,sal into pename,psal from emp where empno = '7839';
--打印姓名和薪水
dbms_output.put_line(pename||'的薪水是'||psal);
end;
/1
2
3
4
5
6
7
8--定义记录型变量实现上面的例子
SQL> declare
emp_rec emp % rowtype;
begin
select * into emp_rec from emp where empno = '7839';
dbms_output.put_line(emp_rec.ename||'的薪水是'||emp_rec.sal);
end;
/
2. if语句
1 | --例:判断用户键盘输入的数字 |
3. 循环语句
形式1
1
2
3
4SQL> while total <= 2500 loop
...
total := total+salary;
end loop;例:使用while循环打印1-10
1
2
3
4
5
6
7
8
9SQL> declare
pnum number := 1;
begin
while pnum <= 10 loop
dbms_output.put_line(pnum);
pnum := pnum+1;
end loop;
end;
/形式2
1
2
3
4SQL> loop
exit [when conditions];--当条件成立时退出循环
...
end loop;例:
1
2
3
4
5
6
7
8
9
10SQL> declare
pnum number := 1;
begin
loop
exit when pnum >10;
dbms_output.put_line(pnum);
pnum := pnum+1;
end loop;
end;
/形式3
1
2
3SQL> for i in 1...3 loop --必须是连续区间
...
end loop;例:
1
2
3
4
5
6
7
8SQL> declare
pnum number := 1;
begin
for pnum in 1...10 loop
dbms_output.put_line(pnum);
end loop;
end;
/
三、光标
光标就是一个结果集(result set)。例:
1 | select job into ptilte from emp; |
1. 光标的语法
1 | SQL> cursor 光标名 [(参数名 参数类型,...)] |
从光标中取值:
1 | --打开光标 |
2. 光标的属性
1 | %found;--fetch取到记录则为true |
例:查询并打印员工的姓名和薪水
1 | SQL> set serveroutput on; |
3. 案例:给员工涨工资
1 | --给员工涨工资,总裁1000,经理800,其他400 |
4. 光标数的限制
默认情况下,oracle数据库只允许在同一个会话中打开300个光标
查看参数值
1
2SQL> conn sys/orcl as sysdba;
show parameter cursor;修改光标数的限制
1
2
3
4
5SQL> alter system set open_cursor = 400 scope = both;
--scope取值
both;--两者都更改(当前实例/改参数文件)
memory;--只更改当前实例,不更改参数文件
spfile;--只更改参数文件,不更改当前实例(需要重启数据库)
5. 带参数的光标
例:查询某个部门中员工的姓名
1 | SQL> declare |
四、例外
例外是程序设计语言提供的一种功能,用来增强程序的健壮性和容错性。系统例外:
no_data_found | 没有找到数据 |
---|---|
too_many_rows | select…into语句匹配多个行 |
zero_divide | 被零除 |
value_error | 算术或转换错误 |
timeout_on_resource | 在等待资源时发生超时(典型场景:分布式数据库) |
1. 系统例外之no_data_found
1 | SQL> declare |
2. 系统例外之too_many_rows
1 | SQL> declare |
3. 系统例外之zero_divide
1 | SQL> declare |
4. 系统例外之value_error
1 | SQL> declare |
5. 系统例外之timeout_on_resource
6. 自定义例外
定义变量,类型是exception,使用raise抛出自定义例外
1 | SQL> declare |
五、PL/SQL综合案例
1. 统计每年入职的员工数
1 | SQL> declare |
2. 员工涨工资
从最低工资涨起,每人涨10%,但工资总额不能超过5万元,计算涨工资的人数(次数)和涨后的工资总额
1 | SQL> declare |
分析:涨后的工资总额
- select sum(sal) into saltotal from emp;
- 涨后的工资总额 = 涨前的工资总额 + sal*0.1
- 因为不是每个人都会涨,所以需要得到工资总额初始值,一开始得不到涨后的工资总额
- 注意rollback的使用方法
3. 涉及两张表的统计员工工资
实现按部门分段(6000以上、[6000,3000]、3000以下)统计各工资段的人数以及各个部门的工作总额,不涉及多表查询
创建表保存统计结果
1
2
3
4
5
6
7
8SQL> create table msg
(
deptno number,--部门号
count1 number,--<3000
count2 number,--[3000,6000]
count3 number,-->6000
saltotal number--工资总额
)
1 | SQL> declare |
4. 成绩统计
按系名分段统计(<60,[60,85],>85)”大学物理“课程各分段的学生人数以及各系学生的平均成绩。涉及多表查询(子查询)
1. 分析
sql语句
得到哪些系
1
2SQL> select dno,dname from dep;
--光标--循环--退出条件:notfound得到系中选了”大学物理“课程学生的成绩
1
2
3
4
5
6
7SQL> select grade from sc where cno = (
select cno from course where cname = ? --课程名
)
and sno in (
select sno from student where dno = ? --系名
);
--带参数的光标--循环--退出条件:notfound
变量
- 初始值
- 最终值如何得到
每个分段的人数
count1,count2,count3初始化的位置,第一个循环内,第二个循环外
每个系选了”大学物理“学生的平均成绩
算术运算
查数据库
1
2
3
4
5
6SQL> select avg(grade) into avggrade from sc where cno = (
select cno from course where cname = ?
)
and sno in (
select sno from student where dno = ?
);
性能问题
- 算术运算比较好
- 能不查数据库就不查数据库,查询数据库耗时大
2. 程序
创建msg1保存结果
1
2
3
4
5
6
7
8
9SQL> create table msg1
(
coursename varchar2(20),--课程名称
dname varchar2(20),--系名
count1 number,--<60
count2 number,--[60,85]
count3 number,-->85
avggrade number--平均成绩
)成绩统计
1 | SQL> declare |