📄 第四章 pl-sql的控制结构 - pl-sql用户指南与参考 - whatiswhat.htm
字号:
<TBODY>
<TR>
<TD
noWrap><STRONG>BEGIN</STRONG><BR> ...<BR> <STRONG>IF</STRONG> sales > 50000 <STRONG>THEN</STRONG><BR> bonus := 1500;<BR> <STRONG>ELSIF</STRONG> sales > 35000 <STRONG>THEN</STRONG><BR> bonus := 500;<BR> <STRONG>ELSE</STRONG><BR> bonus := 100;<BR> <STRONG>END</STRONG> <STRONG>IF</STRONG>;<BR><BR> <STRONG>INSERT</STRONG> <STRONG>INTO</STRONG> payroll<BR> <STRONG>VALUES</STRONG> (emp_id, bonus, ...);<BR><STRONG>END</STRONG>;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>如果sales的值大于50000的话,第一个和第二个条件就为真。然而,bonus只会被赋予1500的值,因为第二个条件并没有执行到。当第一个条件为真的话,它关联的语句就会执行,然后控制权转到INSERT语句。
</P>
<P class=title2>4、CASE语句</P>
<P>同IF语句一样,CASE语句也是选出一个语句序列来执行。但是,为了选择出合适的语句序列,CASE会使用一个选择器,而不是多个布尔表达式。想要比较IF和CASE语句的话,请看下面对学校成绩的描述信息:
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>IF</STRONG> grade = <EM>'A'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Excellent'</EM>);<BR><STRONG>ELSIF</STRONG> grade = <EM>'B'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Very Good'</EM>);<BR><STRONG>ELSIF</STRONG> grade = <EM>'C'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Good'</EM>);<BR><STRONG>ELSIF</STRONG> grade = <EM>'D'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Fair'</EM>);<BR><STRONG>ELSIF</STRONG> grade = <EM>'F'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Poor'</EM>);<BR><STRONG>ELSE</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'No such grade'</EM>);<BR><STRONG>END</STRONG> <STRONG>IF</STRONG>;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>请注意这五个布尔表达式,在每一个实例中,我们只对同一变量的值进行检测,看它的分数值是否等于"A"、"B"、"C"、"D"、"E"或"F"。下面我们用CASE语句重新编写上面的程序:
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>CASE</STRONG> grade<BR> <STRONG>WHEN</STRONG> <EM>'A'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Excellent'</EM>);<BR> <STRONG>WHEN</STRONG> <EM>'B'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Very Good'</EM>);<BR> <STRONG>WHEN</STRONG> <EM>'C'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Good'</EM>);<BR> <STRONG>WHEN</STRONG> <EM>'D'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Fair'</EM>);<BR> <STRONG>WHEN</STRONG> <EM>'F'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Poor'</EM>);<BR> <STRONG>ELSE</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'No such grade'</EM>);<BR><STRONG>END</STRONG> <STRONG>CASE</STRONG>;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>CASE语句的可读性高而且高效,所以,如果可能的话,尽量把IF-THEN-ELEIF都改写成CASE语句。
</P>
<P>CASE语句以关键字CASE开头,然后跟上一个选择器,也就是上例中的变量grade。选择器表达式可能是很复杂的。例如,它有可能是一个函数调用。但在通常情况下,它只是一个独立的变量。选择器表达式只被计算一次。它的值可以是除BLOB、BFILE、对象类型、PL/SQL记录、索引表、变长数组或嵌套表之外的任何有效的PL/SQL数据类型。
</P>
<P>选择器后面跟着一个或多个WHEN子句,它们是按顺序检测的。选择器的值决定了哪个子句被执行。如果选择器的值等于WHEN子句的表达式值,
WHEN子句中的语句序列就会被执行。例如在上面例子中,如果grade等于"C",程序就会输出"Good"。当WHEN子句中的语句序列被执行完毕,控制权会转到下一个语句,而不会再执行后续的WHEN子句。
</P>
<P>ELSE子句的工作原理与IF中的类似。上例子中,如果grade的值不与任何一个WHEN子句匹配,ELSE部分就会被执行,"No
such
grade"就会被输出。ELSE子语是可选的。但是,如果我们省略了ELSE子句,PL/SQL就会为我们添加隐式的ELSE子句:
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>ELSE</STRONG> <STRONG>RAISE</STRONG> CASE_NOT_FOUND;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>如果CASE语句选择了隐式的ELSE子句,PL/SQL就会抛出预定义异常CASE_NOT_FOUND。所以,即使我们省略了ELSE子句,ELSE也会有一个默认的动作。
</P>
<P>关键字END CASE是CASE语句结束的标志。这两个关键字必须用空格分开。形式如下: </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap>[<<label_name>>]<BR><STRONG>CASE</STRONG> selector<BR> <STRONG>WHEN</STRONG> expression1 <STRONG>THEN</STRONG><BR> sequence_of_statements1;<BR> <STRONG>WHEN</STRONG> expression2 <STRONG>THEN</STRONG><BR> sequence_of_statements2;<BR> ...<BR> <STRONG>WHEN</STRONG> expressionn <STRONG>THEN</STRONG><BR> sequence_of_statementsn;<BR> [<STRONG>ELSE</STRONG> sequence_of_statementsN+1;]<BR><STRONG>END</STRONG> <STRONG>CASE</STRONG> [label_name];
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>同PL/SQL块一样,CASE语句也是可以加标签的。标签是一个未声明的标识符,必须出现在CASE语句的开头,用双尖括号夹起来。标签的名称也可以出现在CASE语句的结尾处,但不是必须的。
</P>
<P>CASE语句中的异常会按正常的方法处理,就是说正常的执行语句停止,控制权转到PL/SQL块或子程序的异常控制部分。
</P>
<UL>
<LI>搜寻式CASE语句 </LI></UL>
<P>PL/SQL还提供下面搜寻形式的CASE语句: </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap>[<<label_name>>]<BR><STRONG>CASE</STRONG><BR> <STRONG>WHEN</STRONG> search_condition1 <STRONG>THEN</STRONG><BR> sequence_of_statements1;<BR> <STRONG>WHEN</STRONG> search_condition2 <STRONG>THEN</STRONG><BR> sequence_of_statements2;<BR> ...<BR> <STRONG>WHEN</STRONG> search_conditionn <STRONG>THEN</STRONG><BR> sequence_of_statementsn;<BR> [<STRONG>ELSE</STRONG> sequence_of_statementsN+1;]<BR><STRONG>END</STRONG> <STRONG>CASE</STRONG> [label_name];
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>搜寻式CASE语句没有选择器。并且,它的WHEN子句只能包含结果为布尔类型的表达式,产生其它类型结果的表达式是不允许的。示例如下:
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>CASE</STRONG><BR> <STRONG>WHEN</STRONG> grade = <EM>'A'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Excellent'</EM>);<BR> <STRONG>WHEN</STRONG> grade = <EM>'B'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Very Good'</EM>);<BR> <STRONG>WHEN</STRONG> grade = <EM>'C'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Good'</EM>);<BR> <STRONG>WHEN</STRONG> grade = <EM>'D'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Fair'</EM>);<BR> <STRONG>WHEN</STRONG> grade = <EM>'F'</EM> <STRONG>THEN</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'Poor'</EM>);<BR> <STRONG>ELSE</STRONG><BR> DBMS_OUTPUT.put_line(<EM>'No such grade'</EM>);<BR><STRONG>END</STRONG> <STRONG>CASE</STRONG>;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>搜寻条件是按顺序计算的。每个搜寻条件的布尔值决定了哪个WHEN子句被执行。一旦WHEN子句被执行,控制权就会被交给下一个语句,后续的搜寻条件就不会被考虑。
</P>
<P>如果没有找到搜寻条件为TRUE的子句,ELSE子句就会执行。ELSE虽然是可选的,但是,如果省略了ELSE,PL/SQL就会添加隐式的ELSE子句:
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>ELSE</STRONG> <STRONG>RAISE</STRONG> CASE_NOT_FOUND;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>如果执行过程中有异常发生,我们可以在块或子程序的异常控制部分捕获到。 </P>
<P class=title2>5、PL/SQL条件控制语句使用准则</P>
<P>我们不应该像下面这样使用笨拙的IF语句: </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>IF</STRONG> new_balance < minimum_balance <STRONG>THEN</STRONG><BR> overdrawn := <STRONG>TRUE</STRONG>;<BR><STRONG>ELSE</STRONG><BR> overdrawn := <STRONG>FALSE</STRONG>;<BR><STRONG>END</STRONG> <STRONG>IF</STRONG>;<BR><BR>...<BR><BR><STRONG>IF</STRONG> overdrawn = <STRONG>TRUE</STRONG> <STRONG>THEN</STRONG><BR> <STRONG>RAISE</STRONG> insufficient_funds;<BR><STRONG>END</STRONG> <STRONG>IF</STRONG>;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>上面的代码忽视了两个地方。首先,布尔表达式的值可以直接赋给布尔变量。所以我们可以把第一个IF语句简化成下面的语句形式:
</P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap>overdrawn := new_balance < minimum_balance;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>第二,布尔变量本身就是TRUE或FALSE。所以,在IF的条件表达式中直接使用变量本身即可: </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>IF</STRONG> overdrawn <STRONG>THEN</STRONG> ...
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>尽可能地使用ELSIF子句代替嵌套IF语句。这样我们的代码就更易读易理解。比较下面两个IF语句: </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>IF</STRONG> condition1 <STRONG>THEN</STRONG><BR> statement1;<BR><STRONG>ELSE</STRONG><BR> <STRONG>IF</STRONG> condition2 <STRONG>THEN</STRONG><BR> statement2;<BR> <STRONG>ELSE</STRONG><BR> <STRONG>IF</STRONG> condition3 <STRONG>THEN</STRONG><BR> statement3;<BR> <STRONG>END</STRONG> <STRONG>IF</STRONG>;<BR> <STRONG>END</STRONG> <STRONG>IF</STRONG>;<BR><STRONG>END</STRONG> <STRONG>IF</STRONG>;
</TD>
<TD vAlign=top
noWrap><STRONG>IF</STRONG> condition1 <STRONG>THEN</STRONG><BR> statement1;<BR><STRONG>ELSIF</STRONG> condition2 <STRONG>THEN</STRONG><BR> statement2;<BR><STRONG>ELSIF</STRONG> condition3 <STRONG>THEN</STRONG><BR> statement3;<BR><STRONG>END</STRONG> <STRONG>IF</STRONG>;</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>这两个语句在逻辑上是等价的,但第一个语句看起来有些混乱,而第二个就较为明显。 </P>
<P>如果把单独一个表达式与多个值进行比较的话,我们可以使用CASE语句来代替多个ELSIF子句。 </P>
<P class=title1>三、循环控制:LOOP和EXIT语句</P>
<P>LOOP语句能让我们反复执行一个语句序列。有三种形式的LOOP语句:LOOP,WHILE-LOOP和FOR-LOOP。
</P>
<P class=title2>1、LOOP</P>
<P>LOOP语句最简单的形式就是把语句序列放到关键字LOOP和END LOOP之间,语法如下: </P>
<BLOCKQUOTE>
<TABLE>
<TBODY>
<TR>
<TD
noWrap><STRONG>LOOP</STRONG><BR> sequence_of_statements;<BR><STRONG>END</STRONG> <STRONG>LOOP</STRONG>;
</TD></TR></TBODY></TABLE></BLOCKQUOTE>
<P>在每一个循环中,语句序列都会被顺序执行,然后再返回循环顶部从头执行。如果不想继续执行,可以使用EXIT语句退出循环。我们可以把一个或多个EXIT语句放到循环里,但不能放到循环外面。有两种形式的EXIT语句:EXIT和EXIT-WHEN。
</P>
<UL>
<LI>EXIT </LI></UL>
<P>EXIT语句会强迫循环无条件终止。当遇到EXIT语句时,循环会立即终止,并把控制权交给下面的语句。示例如下:
</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -