7.4.3 LOOP循环控制语句

LOOP语句也叫循环语句,它能让我们重复地执行指定的语句块。LOOP语句有以下四种形式:

❑LOOP;

❑WHILE…LOOP;

❑FOR…LOOP;

❑CURSOR FOR LOOP。

本小节将介绍前三种类型,至于CURSOR FOR LOOP会在第8章中介绍。

1.基本的LOOP

该形式的语句属于LOOP循环控制语句中最基本的结构,它会重复不断地执行LOOP和END LOOP之间的语句序列。由于基本的LOOP语句本身没有包含中断循环的条件,所以通常情况下都是和其他的条件控制语句一起使用,利用EXIT、GOTO等可以中断LOOP循环。当然,异常也能使LOOP语句中断。图7.21描述了基本的LOOP语句的流程。

7.4.3 LOOP循环控制语句 - 图1

图 7.21 LOOP语句流程

基本的LOOP语句语法结构如下:


[<<label_name>>]

LOOP

statement…

END LOOP[label_name]


【语法说明】

❑<<label_name>>:LOOP语句的标签,是可选项。

❑LOOP:LOOP循环的开始标志。

❑statement:LOOP语句中需要重复执行的语句。

❑END LOOP:LOOP循环结束标志。

基本的LOOP语句需要和条件控制语句一起使用,否则会出现死循环的情况,直到内存溢出时抛出异常才能终止循环。通常情况下,正常终止循环的方式有以下两种:

1)在LOOP循环当中可以使用IF语句与EXIT的组合来结束循环。EXIT必须在循环体内部,它可以使循环正常无条件终止,并且终止循环后程序会正常执行循环外的语句。它如果同IF语句一起使用,表示当满足某个条件时程序退出循环体,继续向后执行。

【示例18】基本LOOP操作示例

示例简单地演示了LOOP的使用方式,要求每次循环都需要为变量增加1,并把变量输出到屏幕。当变量值大于5的时候,要求终止循环。具体脚本如下:


01 DECLARE

02 v_num NUMBER(8):=1;

03 BEGIN

04 <<basic_loop>>

05 LOOP

06 DBMS_OUTPUT.put_line('当前v_num变量的值是:'||v_num);

07 v_num:=v_num+1;

08 IF v_num>5 THEN

09 DBMS_OUTPUT.put_line('退出!当前v_num的值是'||v_num);

10 EXIT basic_loop;

11 END IF;

12 END LOOP;

13 DBMS_OUTPUT.put_line('LOOP循环已经结束!');

14 END;

15 /


【代码解析】

❑第1行为声明变量,默认值为1。

❑第4行是LOOP循环的标签,可以选择性地填写。

❑第5~12行属于一个基本的LOOP结构。

❑第7行表示每循环一次都为变量增加1。

❑第8~10行是条件语句,表示当变量v_num大于5时会退出循环。

❑第10行表示退出语句。basic_loop为LOOP的标签,这里表示的含义是退出标签名为basic_loop的循环。

【执行效果】

在SQL*Plus中执行以上脚本,查看执行结果。执行过程见图7.22。

7.4.3 LOOP循环控制语句 - 图2

图 7.22 LOOP中利用IF条件结束循环

EXIT默认是终止退出当前的循环,但如果使用标签,可以终止并退出指定的LOOP循环。

2)使用EXIT…WHEN语句来结束循环。这种方式在游标中会经常使用,这种情况会在后面的章节见到。它所代表的含义是:当WHEN后面的条件为TRUE时,EXIT会被触发,终止退出指定的循环,如果EXIT后不加LOOP标签,则表示终止退出当前循环。该语句可以替换简单的IF语句,下面的示例将演示这一点。

【示例19】EXIT…WHEN语句使用示例

要求使用EXIT…WHEN替换示例18中的IF语句。脚本如下:


01 DECLARE

02 v_num NUMBER(8):=1;

03 BEGIN

04 <<basic_loop>>

05 LOOP

06 DBMS_OUTPUT.put_line('当前v_num变量的值是:'||v_num);

07 v_num:=v_num+1;

08 EXIT basic_loop WHEN v_num>5;

09 END LOOP;

10

11 DBMS_OUTPUT.put_line('退出!当前v_num的值是'||v_num);

12 DBMS_OUTPUT.put_line('LOOP循环已经结束!');

13 END;

14 /


【代码解析】

❑第8行,利用EXIT…WHEN语句判断变量v_num如果大于5,则退出basic_loop循环。完成判断并退出,只需要一行脚本。

【执行效果】

在SQL*Plus中执行程序,查看结果是否与示例18相同。执行过程见图7.23。

7.4.3 LOOP循环控制语句 - 图3

图 7.23 LOOP中利用EXIT…WHEN语句结束循环

从图7.23的执行结果中可以看出,EXIT…WHEN语句在某些时候可以替代IF语句,而EXIT…WHEN语句更为简洁。建议读者如非必要,LOOP循环当中可以优先考虑该类型的语句。

2.WHILE…LOOP语句

WHILE…LOOP结构的语句本身可以终止LOOP循环,当WHILE后面的布尔表达式为TRUE时,LOOP和END LOOP之间的语句集将执行一次,而后会重新判断WHILE后面的表达式是否为TRUE。其流程见图7.24。

7.4.3 LOOP循环控制语句 - 图4

图 7.24 WHILE…LOOP流程

该语句结构的具体语法如下:


[<<label_name>>]

WHILE boolean_expression

LOOP

statement…

END LOOP[label_name];


语法中的boolean_expression项是一个布尔表达式,只有当该表达式为TRUE的时候,statement部分才能得到执行。其他部分和基本的LOOP语句没有区别。

【示例20】WHILE…LOOP语句示例

要求输出20以内能被3整除的数。脚本如下:


01 DECLARE

02 v_num NUMBER(8):=1;

03 BEGIN

04 DBMS_OUTPUT.put('当前v_num变量的值是:');

05 <<while_loop>>

06 WHILE v_num<20

07 LOOP

08 IF MOD(v_num,3)=0 THEN

09 DBMS_OUTPUT.put(v_num||'');

10 END IF;

11

12 v_num:=v_num+1;

13 END LOOP;

14

15 DBMS_OUTPUT.put_line('退出!当前v_num的值是'||v_num);

16 DBMS_OUTPUT.put_line('LOOP循环已经结束!');

17 END;

18 /


【代码解析】

❑第2行表示声明变量v_num,默认值为1。

❑第5~13行是WHILE…LOOP语句。

❑第5行是WHILE…LOOP语句的标签。

❑第6行表示当变量v_num<20时,执行下面的LOOP循环。

❑第8~10行利用SQL函数判断v_num是否能被3整除。如果整除,则把该值输出。

❑第12行表示每次循环都为变量v_num增加1。这样就可以判断1~20之间所有的数是否能被3整除。而且当变量增加到20时,循环会终止退出。

【执行效果】

在SQL*Plus中执行以上脚本,执行过程见图7.25。

7.4.3 LOOP循环控制语句 - 图5

图 7.25 WHILE…LOOP执行过程

这种结构模式执行的顺序是先判断后循环,所以LOOP中的语句序列有可能连一次执行的机会都没有。例如,程序中的v_num初始值若大于19,LOOP循环将得不到执行。想要避免此类情况,可以采用下列脚本的方式:


01 …

02 WHILE v_bol

03 LOOP

04 IF MOD(v_num,3)=0 THEN

05 DBMS_OUTPUT.put(v_num||'');

06 END IF;

07

08 IF v_num>=20 THEN

09 v_bol:=FALSE;

10 END IF;

11 v_num:=v_num+1;

12 END LOOP;

13 …


【代码解析】

❑第2行的v_bol是一个布尔类型的变量,默认值为TRUE类型。一旦该变量值为FALSE,循环将终止退出。

❑第8~10行判断变量v_num,如果该变量的值大于等于20,变量v_bol的值将被置为FALSE。

经过修改以后,它的执行顺序和Java语言当中的DO-WHILE语句执行顺序相同。这种方式读者应该掌握。

3.FOR…LOOP

FOR…LOOP语句循环遍历指定范围内的整数。该范围被FOR和LOOP关键词封闭。当第一次进入循环时,其循环范围会被确定,并且以后不会再次计算。每循环一次,其循环次数将会增加1。

FOR…LOOP语句的语法结构如下:


01 [<<label_name>>]

02 FOR index_name IN

03 [REVERSE]

04 lower_bound..upper_bound

05 LOOP

06 statement…

07 END LOOP[label_name];


【语法说明】

❑index_name:循环计数器,该变量可以得到当前的循环次数,但是不能为其赋值。

❑REVERSE:该项指定循环的方式。默认的循环方式是由下标界到上标界,也就是从lower_bound到upper_bound,如果使用REVERSE关键词,那么循环方式正好相反,也就是从上标界到下标界。

❑lower_bound:循环范围的下标界。

❑upper_bound:循环范围的上标界。

❑lower_bound和upper_bound两者需要用“..”连接。

【示例21】FOR…LOOP语句使用示例

该示例算出1~20之间所有整数的和。脚本如下:


01 DECLARE

02 v_num NUMBER(8):=0;

03 BEGIN

04 DBMS_OUTPUT.put('1~20之间整数和:');

05 <<for_loop>>

06 FOR inx IN 1..20 LOOP

07 v_num:=v_num+inx;

08 END LOOP;

09

10 DBMS_OUTPUT.put_line(v_num);

11 DBMS_OUTPUT.put_line('LOOP循环已经结束!');

12 END;

13 /


【代码解析】

❑第2行表示声明变量。

❑第5~8行是一个FOR…LOOP结构。

❑第6行表示循环范围从1到20。inx为循环计数器名。当inx等于20时,循环会自动退出。

❑第7行表示求出1~20之间整数的和。

【执行效果】

在SQL*Plus中执行该脚本,执行过程见图7.26。

7.4.3 LOOP循环控制语句 - 图6

图 7.26 FOR…LOOP语句执行过程

FOR…LOOP循环当中的循环范围可以动态地获取。例如,示例中的下标界完全可以用数值型的变量替代。

需要说明的是,当lower_bound和upper_bound相等时,循环中的语句只能执行一次。