PL/SQL 包含在称之为块的结构中;
如果要创建一个存储过程或程序包,应当给PL/SQL代码块起一个名字;
如果没有给PL/SQL代码块起名字,给代码块被称为匿名块。
- 声明Declaration:定义并初始化块中使用的变量和游标
- 可执行命令Executable Command:用流控制命令(如if命令和循环)执行命令并给声明的变量赋值
- 异常处理Exception Handing:提供对错误情况的定制处理
典型的PL/SQL块结构如下所示:
declare <declaration section> begin <executable command> exception <exception handing> end;
声明部分:
声明部分是P/SQL块的开始,声明部分以declare关键字开始,后面是变量和游标的定义列表。
用户可以定义具有常量值的变量,并且变量能够继承已存在的列和查询结构中的数据类型。
程序:
计算一个圆的面积,并将结果保存到一个名为AREAS的表中,AREAS表有两列,分别用于存储半径和面积。
计算圆面积的公式为半径的平方乘以常量π。
declare pi constant NUMBER(9,7) := 3.1415927; radius INTEGER(5); area NUMBER(14,2); begin radius := 3; area := pi*power(radius, 2); insert into AREAS values (radius, area); end; /
/ - 用于执行PL/SQL块。
执行之后,将会得到Oracle的响应信息:
PL/SQL procedure successfully completed.
程序:
声明一个游标来检索RADIUS_VALS表中的记录。
RADIUS_VALS表只有一列-Radius列,它用来保存示例使用的半径。
该游标在声明部分声明,rad_val变量被声明为基于游标结果的数据类型。
declare pi constant NUMBER(9,7) := 3.1415927; area NUMBER(14,2); cursor rad_cursor is select * from RADIUS_VALS; rad_val rad_cursor%ROWTYPE; begin open rad_cursor; fetch rad_cursor into rad_val; area := pi*power(rad_val.radius, 2); insert into AREAS values (rad_val.radius, area); close rad_cursor; end; /
采用%ROWTYPE %TYPE定义数据类型的优点:可以使PL/SQL代码中数据类型的定义与基础数据结构无关。
可执行部分:
在关键字begin之后,PL/SQL块开始工作。
条件逻辑:
在PL/SQL中,可以使用if,else,elsif,continue和case命令来控制可执行命令部分的命令流。
if <some condition> then <some command> elsif <some condition> then <some command> else <some command> end if;
if条件可以相互嵌套
if <some condition> then if <some condition> then <some command> end if; else <some command> end if;
通过if嵌套,可以快速开发出复杂的逻辑流程;
但是,不要使流程过于复杂,应当经常检查逻辑条件是否能够组合成更简单的形式。
程序:
如果圆面值大于,插入AREAS表。
declare pi constant NUMBER(9,7) := 3.1415927; area NUMBER(14,2); cursor rad_cursor is select * from RADIUS_VALS; rad_val rad_cursor%ROWTYPE; begin open rad_cursor; fetch rad_cursor into rad_val; area := pi*power(rad_val.radius, 2); if area > 30 then insert into AREAS values (rad_val.radius, area); end if; close rad_cursor; end; /
循环:
- 简单循环 - 直到循环中遇到exit或exit或exit when语句时,才跳出循环
- FOR循环 - 指定循环次数的循环
- WHILE循环 - 在满足某个条件时循环
程序 - 简单循环:
在AREAS表中生成多行,此循环一loop关键字开始,exit when子句确定何时退出循环。
end loop子句标识循环的结束。
declare pi constant NUMBER(9,7) := 3.1415927; radius INTEGER(5); area NUMBER(14,2); begin radius := 3; loop area := pi*power(radius, 2); insert into AREAS values (radius, area); radius := radius+1; exit when area > 100; end loop; end; /
程序 - 简单的游标循环:
可以使用游标的属性作为退出循环的条件;
- %FOUND - 可以从游标中取出1条记录
- %NOTFOUND - 不能从游标中取到记录
- %ISOPEN - 游标已经打开
- %ROWCOUNT - 迄今为止从游标中取出的行数
declare pi constant NUMBER(9,7) := 3.1415927; area NUMBER(14,2); cursor rad_cursor is select * from RADIUS_VALS; rad_val rad_cursor%ROWTYPE; begin open rad_cursor; loop fetch rad_cursor into rad_val; exit when rad_cursor%NOTFOUND; area := pi*power(rad_val.radius, 2); insert into AREAS values (rad_val.radius, area); end loop; close rad_cursor; end; /
程序 - FOR循环:
在FOR循环中,循环执行指定次数。
FOR循环的开始由关键字for指定,后面是用来决定循环过程中何时完成以及循环何时退出的条件。
由于循环执行的次数在循环开始的时候设置,因此在循环中不需要exit命令。
declare pi constant NUMBER(9,7) := 3.1415927; radius INTEGER(5); area NUMBER(14,2); begin for radius in 1..7 loop area := pi*power(radius, 2); insert into AREAS values (radius, area); end loop; end; /
程序 - 游标FOR循环:
在游标FOR循环中,循环执行的次数由查询的结果动态决定。
在游标FOR循环中,打开游标,取出游标和关闭游标隐式完成,不需要显式指定这些操作。
declare pi constant NUMBER(9,7) := 3.1415927; area NUMBER(14,2); cursor rad_cursor is select * from RADIUS_VALS; begin for rad_val in rad_cursor loop area := pi*power(rad_val.radius, 2); insert into AREAS values (rad_val.radius, area); end loop; end; /
请注意:rad_val没有在块中显式地声明。
程序 - WHILE循环:
知道满足退出条件,WHILE循环才会结束。
在循环中用while命令指定退出循环的条件。
delete from AREAS; declare pi constant NUMBER(9,7) := 3.1415927; radius INTEGER(5); area NUMBER(14,2); begin radius := 3; while radius <=7 loop area := pi*power(radius, 2); insert into AREAS values (radius, area); radius := radius+1; end loop; end; /
使用CONTINUE 和 CONTINUE WHEN语句
可以在循环中使用continue语句退出循环的当前迭代,并将控制权转交给下一次迭代。
例如:如果通过一组计数器值进行迭代,就可以跳过指定的值而不完全退出循环。
declare pi constant NUMBER(9,7) := 3.1415927; radius INTEGER(5); area NUMBER(14,2); begin radius := 1; loop if radius < 5 then continue; end if; area := pi*power(radius, 2); insert into AREAS values (radius, area); radius := radius + 1; exit when area > 100; end loop; end; /
也可以直接使用continue when radius < 5
CASE语句
可以使用case语句控制PL/SQL块中的分支逻辑。
例如,可以使用case语句按条件赋值,或者在插入值之前进行转换。
declare pi constant NUMBER(9,7) := 3.1415927; area NUMBER(14,2); cursor rad_cursor is select * from RADIUS_VALS; rad_val rad_cursor%ROWTYPE; begin open rad_cursor; loop fetch rad_cursor into rad_val; exit when rad_cursor%NOTFOUND; area := pi*power(rad_val.radius, 2); case when rad_val.radius = 3 then insert into AREAS values (rad_val.radius, area); when rad_val.radius = 4 then insert into AREAS values (rad_val.radius, area); when rad_val.radius = 10 then insert into AREAS values (0, 0); else raise CASE_NOT_FOUND; end case; end loop; close rad_cursor; end; /
如果省略else关键字,则PL/SQL隐式增加以下else子句:
else raise CASE_NOT_FOUND;
case子句经常用于把一列值转换成相应的说明。
异常处理部分
在异常处理部分,用when子句判断出发哪个异常,即执行哪段代码。
如果在PL/SQL块的可执行部分触发一个异常,则命令流立即退出可以执行命令部分
并在异常处理部分中搜索与遇到的错误相匹配的异常。
PL/SQL提供了一组系统定义的异常,并允许用户自定义的异常。
异常部分总是以exception关键字开始,并放在终止PL/SQL块的可执行命令部分的end命令之前。
declare <declarations section> begin <executable command> exception <exception handing> end;
PL/SQL 块中异常处理部分是可选的。
程序 - 异常处理:
当除以零的情况下,会有错误出现,需要exception处理。
declare pi constant NUMBER(9,7) := 3.1415927; radius INTEGER(5); area NUMBER(14,2); some_variable NUMBER(14,2); begin radius := 3; loop some_variable := 1/(radius -4); area := pi*power(radius, 2); insert into AREAS values (radius, area); radius := radius+1; exit when area > 100; end loop; exception when ZERO_DIVIDE then insert into AREAS values(0,0); end; /
可以使用when others子句处理在异常处理部分中未定义过的所有异常。
一旦遇到异常,就不能返回到可执行命令部分中正常的命令处理流了。
如果需要保持在可执行命令部分中,就应当在程序遇到可能的异常之前用if条件去测试它们。