PL SQL 用户指南和参考第四章PLSQL的控制结构.docx
- 文档编号:8809392
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:22
- 大小:42.55KB
PL SQL 用户指南和参考第四章PLSQL的控制结构.docx
《PL SQL 用户指南和参考第四章PLSQL的控制结构.docx》由会员分享,可在线阅读,更多相关《PL SQL 用户指南和参考第四章PLSQL的控制结构.docx(22页珍藏版)》请在冰豆网上搜索。
PLSQL用户指南和参考第四章PLSQL的控制结构
第四章PL/SQL的控制结构
一、PL/SQL控制结构一览
根据结构定理(structuretheorem),任何计算机程序都可以用下图中的基本控制结构来表示。
它们可以任意组合来解决问题。
选择结构是用于测试条件的,根据条件的真假,执行一系列语句。
一个条件语句可以是任何能够返回布尔值(TRUE或FALSE)的变量或表达式。
循环结构能在条件满足的情况下反复执行。
序列结构只是简单的按照顺序执行语句。
二、条件控制:
IF和CASE语句
有时候,我们需要根据具体的条件来采取不同的对策。
IF语句就能让我们按条件来执行语句序列。
也就是说,语句序列的执行与否取决于某个给定的条件。
有三种IF语句:
IF-THEN、IF-THEN-ELSE和IF-THEN-ELSIF。
CASE语句是条件判断的精简形式,它能计算条件表达式的值并在多个对应动作中做出选择。
1、IF-THEN语句
IF语句最简单的形式就是把一个条件和一个语句序列用关键字THEN和ENDIF关联起来:
IF condition THEN
sequence_of_statements
END IF;
只有在条件值为真的时候语句序列才能被执行。
如果条件值为假或是空,IF语句就什么都不做。
无论哪种情况,控制权最后还是会被传递到下一个语句,如下例:
IF sales > QUOTA THEN
compute_bonus(empid);
UPDATE payroll
SET pay = pay + bonus
WHERE empno = emp_id;
END IF;
如果我们把IF语句放到一行,就可以像下面这样编写:
IF x > y THEN high :
= x; END IF;
2、IF-THEN-ELSE语句
第二种形式的IF语句使用关键字ELSE添加了一个额外的处理选项,如下:
IF condition THEN
sequence_of_statements1
ELSE
sequence_of_statements2
END IF;
当条件为假或空时,ELSE子句中的语句序列就会被执行。
下例中,第一个UPDATE语句在条件为真的情况下执行,而第二个UPDATE语句在条件为假或为空的情况下才会被执行:
IF trans_type = 'CR' THEN
UPDATE accounts
SET balance = balance + credit
WHERE ...
ELSE
UPDATE accounts
SET balance = balance - debit
WHERE ...
END IF;
THEN和ELSE子句中也可以包含IF语句。
就是说IF语句能够被嵌套使用,如下例所示:
IF trans_type = 'CR' THEN
UPDATE accounts
SET balance = balance + credit
WHERE ...
ELSE
IF new_balance >= minimum_balance THEN
UPDATE accounts
SET balance = balance - debit
WHERE ...
ELSE
RAISE insufficient_funds;
END IF;
END IF;
3、IF-THEN-ELSIF语句
有时我们可能需要从几个选项中选择一个,这时我们就需要使用第三种IF语句,添加一个ELSIF关键字提供额外的条件选项,使用方法如下:
IF condition1 THEN
sequence_of_statements1
ELSIF condition2 THEN
sequence_of_statements2
ELSE
sequence_of_statements3
END IF;
如果第一个条件为假或空,ELSIF子句就会检测另外一个条件。
一个IF语句可以有多个ELSIF子句;最后一个ELSE子句是可选的。
条件表达式从上而下的计算。
只要有满足的条件,与它关联的语句就会执行,然后控制权转到下一个语句。
如果所有的条件都为假或是空,ELSE部分的语句就会执行。
看一下下面的例子:
BEGIN
...
IF sales > 50000 THEN
bonus :
= 1500;
ELSIF sales > 35000 THEN
bonus :
= 500;
ELSE
bonus :
= 100;
END IF;
INSERT INTO payroll
VALUES (emp_id, bonus, ...);
END;
如果sales的值大于50000的话,第一个和第二个条件就为真。
然而,bonus只会被赋予1500的值,因为第二个条件并没有执行到。
当第一个条件为真的话,它关联的语句就会执行,然后控制权转到INSERT语句。
4、CASE语句
同IF语句一样,CASE语句也是选出一个语句序列来执行。
但是,为了选择出合适的语句序列,CASE会使用一个选择器,而不是多个布尔表达式。
想要比较IF和CASE语句的话,请看下面对学校成绩的描述信息:
IF grade = 'A' THEN
DBMS_OUTPUT.put_line('Excellent');
ELSIF grade = 'B' THEN
DBMS_OUTPUT.put_line('Very Good');
ELSIF grade = 'C' THEN
DBMS_OUTPUT.put_line('Good');
ELSIF grade = 'D' THEN
DBMS_OUTPUT.put_line('Fair');
ELSIF grade = 'F' THEN
DBMS_OUTPUT.put_line('Poor');
ELSE
DBMS_OUTPUT.put_line('No such grade');
END IF;
请注意这五个布尔表达式,在每一个实例中,我们只对同一变量的值进行检测,看它的分数值是否等于"A"、"B"、"C"、"D"、"E"或"F"。
下面我们用CASE语句重新编写上面的程序:
CASE grade
WHEN 'A' THEN
DBMS_OUTPUT.put_line('Excellent');
WHEN 'B' THEN
DBMS_OUTPUT.put_line('Very Good');
WHEN 'C' THEN
DBMS_OUTPUT.put_line('Good');
WHEN 'D' THEN
DBMS_OUTPUT.put_line('Fair');
WHEN 'F' THEN
DBMS_OUTPUT.put_line('Poor');
ELSE
DBMS_OUTPUT.put_line('No such grade');
END CASE;
CASE语句的可读性高而且高效,所以,如果可能的话,尽量把IF-THEN-ELEIF都改写成CASE语句。
CASE语句以关键字CASE开头,然后跟上一个选择器,也就是上例中的变量grade。
选择器表达式可能是很复杂的。
例如,它有可能是一个函数调用。
但在通常情况下,它只是一个独立的变量。
选择器表达式只被计算一次。
它的值可以是除BLOB、BFILE、对象类型、PL/SQL记录、索引表、变长数组或嵌套表之外的任何有效的PL/SQL数据类型。
选择器后面跟着一个或多个WHEN子句,它们是按顺序检测的。
选择器的值决定了哪个子句被执行。
如果选择器的值等于WHEN子句的表达式值,WHEN子句中的语句序列就会被执行。
例如在上面例子中,如果grade等于"C",程序就会输出"Good"。
当WHEN子句中的语句序列被执行完毕,控制权会转到下一个语句,而不会再执行后续的WHEN子句。
ELSE子句的工作原理与IF中的类似。
上例子中,如果grade的值不与任何一个WHEN子句匹配,ELSE部分就会被执行,"Nosuchgrade"就会被输出。
ELSE子语是可选的。
但是,如果我们省略了ELSE子句,PL/SQL就会为我们添加隐式的ELSE子句:
ELSE RAISE CASE_NOT_FOUND;
如果CASE语句选择了隐式的ELSE子句,PL/SQL就会抛出预定义异常CASE_NOT_FOUND。
所以,即使我们省略了ELSE子句,ELSE也会有一个默认的动作。
关键字ENDCASE是CASE语句结束的标志。
这两个关键字必须用空格分开。
形式如下:
[<
CASE selector
WHEN expression1 THEN
sequence_of_statements1;
WHEN expression2 THEN
sequence_of_statements2;
...
WHEN expressionn THEN
sequence_of_statementsn;
[ELSE sequence_of_statementsN+1;]
END CASE [label_name];
同PL/SQL块一样,CASE语句也是可以加标签的。
标签是一个未声明的标识符,必须出现在CASE语句的开头,用双尖括号夹起来。
标签的名称也可以出现在CASE语句的结尾处,但不是必须的。
CASE语句中的异常会按正常的方法处理,就是说正常的执行语句停止,控制权转到PL/SQL块或子程序的异常控制部分。
∙搜寻式CASE语句
PL/SQL还提供下面搜寻形式的CASE语句:
[<
CASE
WHEN search_condition1 THEN
sequence_of_statements1;
WHEN search_condition2 THEN
sequence_of_statements2;
...
WHEN search_conditionn THEN
sequence_of_statementsn;
[ELSE sequence_of_statementsN+1;]
END CASE [label_name];
搜寻式CASE语句没有选择器。
并且,它的WHEN子句只能包含结果为布尔类型的表达式,产生其它类型结果的表达式是不允许的。
示例如下:
CASE
WHEN grade = 'A' THEN
DBMS_OUTPUT.put_line('Excellent');
WHEN grade = 'B' THEN
DBMS_OUTPUT.put_line('Very Good');
WHEN grade = 'C' THEN
DBMS_OUTPUT.put_line('Good');
WHEN grade = 'D' THEN
DBMS_OUTPUT.put_line('Fair');
WHEN grade = 'F' THEN
DBMS_OUTPUT.put_line('Poor');
ELSE
DBMS_OUTPUT.put_line('No such grade');
END CASE;
搜寻条件是按顺序计算的。
每个搜寻条件的布尔值决定了哪个WHEN子句被执行。
一旦WHEN子句被执行,控制权就会被交给下一个语句,后续的搜寻条件就不会被考虑。
如果没有找到搜寻条件为TRUE的子句,ELSE子句就会执行。
ELSE虽然是可选的,但是,如果省略了ELSE,PL/SQL就会添加隐式的ELSE子句:
ELSE RAISE CASE_NOT_FOUND;
如果执行过程中有异常发生,我们可以在块或子程序的异常控制部分捕获到。
5、PL/SQL条件控制语句使用准则
我们不应该像下面这样使用笨拙的IF语句:
IF new_balance < minimum_balance THEN
overdrawn :
= TRUE;
ELSE
overdrawn :
= FALSE;
END IF;
...
IF overdrawn = TRUE THEN
RAISE insufficient_funds;
END IF;
上面的代码忽视了两个地方。
首先,布尔表达式的值可以直接赋给布尔变量。
所以我们可以把第一个IF语句简化成下面的语句形式:
overdrawn :
= new_balance < minimum_balance;
第二,布尔变量本身就是TRUE或FALSE。
所以,在IF的条件表达式中直接使用变量本身即可:
IF overdrawn THEN ...
尽可能地使用ELSIF子句代替嵌套IF语句。
这样我们的代码就更易读易理解。
比较下面两个IF语句:
IF condition1 THEN
statement1;
ELSE
IF condition2 THEN
statement2;
ELSE
IF condition3 THEN
statement3;
END IF;
END IF;
END IF;
IF condition1 THEN
statement1;
ELSIF condition2 THEN
statement2;
ELSIF condition3 THEN
statement3;
END IF;
这两个语句在逻辑上是等价的,但第一个语句看起来有些混乱,而第二个就较为明显。
如果把单独一个表达式与多个值进行比较的话,我们可以使用CASE语句来代替多个ELSIF子句。
三、循环控制:
LOOP和EXIT语句
LOOP语句能让我们反复执行一个语句序列。
有三种形式的LOOP语句:
LOOP,WHILE-LOOP和FOR-LOOP。
1、LOOP
LOOP语句最简单的形式就是把语句序列放到关键字LOOP和ENDLOOP之间,语法如下:
LOOP
sequence_of_statements;
END LOOP;
在每一个循环中,语句序列都会被顺序执行,然后再返回循环顶部从头执行。
如果不想继续执行,可以使用EXIT语句退出循环。
我们可以把一个或多个EXIT语句放到循环里,但不能放到循环外面。
有两种形式的EXIT语句:
EXIT和EXIT-WHEN。
∙EXIT
EXIT语句会强迫循环无条件终止。
当遇到EXIT语句时,循环会立即终止,并把控制权交给下面的语句。
示例如下:
LOOP
...
IF credit_rating < 3 THEN
...
EXIT; -- exit loop immediately
END IF;
END LOOP;
-- control resumes here
下面再举一个不能在PL/SQL块中使用EXIT语句的例子:
BEGIN
...
IF credit_rating < 3 THEN
...
EXIT; -- not allowed
END IF;
END;
记住,EXIT语句必须放在循环内。
如果想在PL/SQL块正常到达程序结尾之前而终止执行,可以使用RETURN语句。
∙EXIT-WHEN
EXIT-WHEN语句可以根据给定的条件跳出循环。
当遇到EXIT语句时,WHEN子句中的表达式值就会被计算。
如果条件满足,循环就会被终止,控制权转到循环语句之后的语句。
示例如下:
LOOP
FETCH c1
INTO ...
EXIT WHEN c1%NOTFOUND; -- exit loop if condition is true
...
END LOOP;
CLOSE c1;
在条件满足之前,循环是不会结束的。
所以,循环里的语句必须要改变循环条件的值。
上例中,如果FETCH语句返回了一行值,WNEN子句中的条件就为假;如果不能返回结果,WNEN子句中的条件就为真,循环就会结束,控制权转入CLOSE语句。
EXIT-WHEN语句可以替代简单的IF语句,例如,比较下面两段代码:
IF count > 100 THEN
EXIT;
END IF;
EXIT WHEN count > 100;
这两个语句在逻辑上是等价的,但EXIT-WHEN语句更容易阅读和理解。
∙循环标签
跟PL/SQL块一样,循环也是可以添加标签。
标签必须出现在LOOP语句的开端,语法如下:
<
LOOP
sequence_of_statements
END LOOP;
而在LOOP语句结束部分出现的标签名称是可选的,语法如下:
<
LOOP
...
END LOOP my_loop;
在LOOP结束部分使用标签名称能够改善可读性。
无论使用哪种EXIT语句形式,都可以结束一个封闭的LOOP块,而不仅仅局限于当前的LOOP块。
只要在我们想结束的封闭LOOP块上添加一个标签,然后像下面这样在EXIT语句中使用这个标签就可以了:
<
LOOP
...
LOOP
...
EXIT outer WHEN ... -- exit both loops
END LOOP;
...
END LOOP outer;
2、WHILE-LOOP
WHILE-LOOP语句用关键字LOOP和ENDLOOP把语句序列封闭起来并与一个布尔条件表达式相关联:
WHILE condition LOOP
sequence_of_statements
END LOOP;
每次循环之前,程序都是计算布尔表达式的值。
如果条件为真,语句序列就会被执行,然后重新返回循环顶部计算布尔表达式的值;如果布尔表达式的值为假或空,控制权就会被交给循环之后的语句。
下面看一个例子:
WHILE total <= 25000 LOOP
...
SELECT sal
INTO salary
FROM emp
WHERE x = x; ...
total :
= total + salary;
END LOOP;
循环的次数是与条件相关的,而且在循环结束之前是未知的。
由于条件是在循环顶部测试的,所以语句序列有可能一次都没有执行。
在上面的例子中,如果total的初始值比25000大,那么条件值就是假,循环就会被跳过。
有些语言有LOOPUNTIL或是REPEATUNTIL这样的结构,在底部测试条件表达式的值。
这样,语句序列就会至少执行一次。
PL/SQL没有这样的结构,但我们可以变通地使用下面的方法来实现这样的功能:
LOOP
sequence_of_statements
EXIT WHEN boolean_expression;
END LOOP;
要保证WHILE循环至少执行一次,在条件表达式中使用初始化过的布尔变量,如下例所示:
done :
= FALSE;
WHILE NOT done LOOP
sequence_of_statements;
done :
= boolean_expression;
END LOOP;
在循环内的语句必须为布尔变量赋上一个新值。
否则循环就会无限地执行下去。
如下例的两个LOOP语句在逻辑上是等价的:
WHILE TRUE LOOP
...
END LOOP;
LOOP
...
END LOOP;
3、FOR-LOOP
FOR语句会在指定的整数范围内进行循环操作。
循环的内容被关键字FOR和LOOP封闭起来。
两个"点"(..)作为范围操作符来使用。
语法如下:
FOR counter IN [REVERSE] lower_bound..higher_bound LOOP
sequence_of_statements
END LOOP;
当首次进入FOR循环时,循环的范围就会被确定下来,并且不会重新计算。
如下例所示,语句序列会执行三次,每执行一次,循环因子就会增加1。
FOR i IN 1 .. 3 LOOP -- assign the values 1,2,3 to i
sequence_of_statements -- executes three times
END LOOP;
下例演示了如果下界值等于上界值,循环中的语句序列只执行一次:
FOR i IN 3 .. 3 LOOP -- assign the values 3 to i
sequence_of_statements -- executes one time
END LOOP;
默认情况下,循环总是从下界到上界。
不过也可以使用REVERSE关键字,让循环从上界往下界执行。
但是要记住,范围的书写格式仍旧是递增顺序的。
FOR i IN REVERSE 1 .. 3 LOOP -- assign the values 3,2,1 to i
sequence_of_statements -- executes three times
END LOOP;
FOR循环里,循环计数器只能当作常量来引用且不能为它赋值,如下例:
FOR ctr IN 1 .. 10 LOOP
IF NOT finished THEN
INSERT INTO ...
VALUES (ctr); -- legal
factor :
= ctr * 2; -- legal
ELSE
ctr :
= 10; -- not allowed
END IF;
END LOOP;
∙迭代法
循环范围的边界可以是文字、变量或表达式,但它们都必须是数字。
否则PL/SQL会抛出预定义异常VALUE_ERROR。
如下例,下界不一定非得是1。
但循环计数器只能是每次增加1。
j IN -5 .. 5
k IN REVERSE first..last
step IN 0..TRUNC(high/low) * 2
在PL/SQL内部,它会把边界值赋给一个临时的PLS_INTEGER变量,并在需要的时候把值转换成最接近的整数。
PLS_INTEGER的范围是-2**31到2**31之间。
所以,如果边界值超过这个范围,我们就会得到一个数字溢出错误:
DECLARE
h
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- PL SQL 用户指南和参考第四章PLSQL的控制结构 用户指南 参考 第四 PLSQL 控制 结构