简介
PL/SQL(Procedure Language/SQL)是Oracle对SQL语言的过程化扩展,在SQL命令语言中增加了过程处理语句(如分支、循环等),使SQL语言具有处理过程的能力。所以PL/SQL是面向过程的语言。对于其他的数据库也有其对应的过程扩展语言,例如DB2的SQL/PL,SQL Server的Transac-SQL(T-SQL)。
程序结构
declare
说明部分(变量说明、光标说明、例外申明)
begin
语句序列(DML语句)
exception
例外处理语句
end;
/
如果没有说明部分,declare可以不需要。
变量
变量可以分为基本类型变量,引用型变量和记录型变量。变量的赋值使用“:=”或者在SQL语句中使用“into”。
基本变量类型有char, varchar2, date, number, boolean, long。
pnumber number(7,2) //定义一个number类型变量,7表示小数点前保留7位,2表示保留两位小数
pname varchar2(20) //定义一个长度为20的varchar2类型变量
pdate date //定义一个date类型变量
pnumber := 1; //赋值
pdate := sysdate; //赋值
select ename into pname from emp where empno = 7839; //使用into赋值ename, empno为字段名, emp为表名
引用型变量为引用表中的字段的类型,如
pname emp.ename%TYPE; //定义一个引用型变量
这表示定义了一个变量“pname”,这个变量的类型和emp表中ename字段的数据类型是一样的。
记录型变量记录表中的一行数据
emp_rec emp%rowtype; //定义一个记录型变量
emp_rec.ename := 'ADAMS'; //引用记录型变量,并把ADMS赋值给记录中的ename字段
select * into emp_rec from emp where empno=7839; //使用into给emp_rec赋值
“emp_rec”代表变量名,emp为表的名字,“ename”为emp表中的一个字段。
条件语句
if语句
-
IF 条件 THEN 执行语句;
END IF; -
IF 条件 THEN 执行语句;
ELSE 执行语句;
END IF; -
IF 条件 THEN 执行语句;
ELSIF 条件 THEN 执行语句;
ELSE 执行语句;
END IF;
循环语句
- WHILE 条件 LOOP
执行语句;
END LOOP; - LOOP
EXIT [WHEN 条件];
执行语句;
END LOOP; - FOR 变量 IN 范围(如1…3) LOOP
执行语句;
END LOOP;
光标
光标(cursor),也称游标,作为集合存储多个值。
光标属性: %found, %notfound,%isopen,%rowcount(影响的行数,而不是总行数,如取到第十行的值时,rowcount即为10)
光标的数量限制:oracle数据库只允许同一个会话中,默认有限个数的光标被打开,一般为300。可在SYS用户下使用show parameter cursor 看到cursor相关的参数,open_cursors即为默认打开的光标数。“alter system set_open_cursors=400 scope=both;”可以更改默认光标数,这里改为了400。
光标的定义:
CURSOR 光标名 [(参数名 数据类型[, 参数名 数据类型]…)] IS SELECT 语句
cursor c1 is select ename from emp;
open c1; //打开光标执行语句
fetch c1 into pename; //取一行数据到变量中, 嵌入循环中可取每一行数据
close c1; //关闭光标释放资源
cursor c2 is select ename, sal from emp; //不带参数的光标的声明
cursor cemp(dno number) is select ename from emp where deptno = dno; //带参数的光标的声明
open cemp(10); //打开带参数的光标时传递参数进去
...
close cemp;
异常(exception)
异常分为系统异常和用户自定义异常。系统异常包括:
No_data_found | 没有找到数据 |
---|---|
Too_many_rows | select…into语句匹配多个行 |
Zero_Divide | 被零除 |
Value_error | 算术或类型转换错误 |
Timeout_on_resource | 在等待资源时发生超时 |
异常处理语句结构
exception
when 异常(no_data_found) then 异常处理语句;
when others(其他异常) then 异常处理语句;
尽量捕获并处理所有的异常,否则直接抛给系统的话,会增加系统负担。
自定义异常:在declare部分定义一个变量,其类型为exception,在执行语句中使用raise关键字抛出自定义异常,并在exception部分处理该异常。
简单例子
/*
以SCOTT用户下的表为例
统计每年入职的员工人数,即1980,1981,1982,1987四年每年的入职人数
*/
set serveroutput on;
declare
--每一位员工入职的年份
cursor cemp is select to_char(hiredate, 'yyyy') from emp;
--年份
phiredate varchar2(5);
--员工入职人数
count80 number := 0;
count81 number := 0;
count82 number := 0;
count87 number := 0;
begin
--打开光标
open cemp;
loop
--取员工入职年份
fetch cemp into phiredate;
--退出条件,这里使用了光标的notfound属性
exit when cemp%notfound;
--根据年份计算数量
if phiredate = '1980' then count80 := count80 + 1;
elsif phiredate = '1981' then count81 := count81 + 1;
elsif phiredate = '1982' then count82 := count82 + 1;
else count87 := count87 + 1;
end if;
end loop;
--关闭光标
close cemp;
--输出结果
dbms_output.put_line('四年总入职人数:' || (count80 + count81 + count82 + count87));
dbms_output.put_line('1980: ' || count80);
dbms_output.put_line('1981: ' || count81);
dbms_output.put_line('1982: ' || count82);
dbms_output.put_line('1987: ' || count87);
end;
/
输出结果为:
四年总入职人数:14
1980: 1
1981: 10
1982: 1
1987: 2