循环是指在程序中重复执行一条或多条语句、PL/SQL中的循环主要有三种:
1.Basic Loop
2. FORLoop
3.WHILE Loop
下面来逐一介绍这三种循环的用法。
一、BasicLoops
基本循环的格式如下:
LOOP
statement1;
...
EXIT [WHENcondition];
END LOOP;
这里的EXIT是用来退出循环的,如果没有EXIT,则会变成死循环。
下面来看一个小例子:
SQL>select location_id, city, country_id fromlocations where country_id = ‘CA‘;
LOCATION_ID CITY CO ----------- ------------------------------ 1800 Toronto CA 1900 Whitehorse CA -- 目前有两条记录
SQL>edit
DECLARE v_countryid locations.country_id%TYPE :=‘CA‘; v_loc_id locations.location_id%TYPE; v_counter NUMBER(2) := 1; v_new_city locations.city%TYPE := ‘Montreal‘; BEGIN SELECT MAX(location_id) INTO v_loc_id FROM locations WHERE country_id =v_countryid; LOOP INSERT INTOlocations(location_id, city, country_id) VALUES((v_loc_id +v_counter), v_new_city, v_countryid); v_counter := v_counter+ 1; EXIT WHEN v_counter> 3; -- EXIT后面可以加上标签,来指定退出哪一层循环 END LOOP; COMMIT; END; /
SQL>/
PL/SQL procedure successfully completed.
SQL>select location_id, city, country_id from locations where country_id = ‘CA‘;
LOCATION_ID CITY CO ----------- ------------------------------ -- 1800 Toronto CA 1900 Whitehorse CA 1901 Montreal CA 1902 Montreal CA 1903 Montreal CA -- 执行了循环语句后,多了三条记录
二、WHILE循环
WHILE循环的格式如下:
WHILE condition LOOP
statement1;
statement2;
...
END LOOP;
WHILE循环是指当condition的结果为TRUE时,就执行循环体。它的循环体可以执行0次或多次,比较适用于循环次数不确定的情况。当条件不满足,就会自动退出循环。
现在使用WHILE循环来改写之前的例子:
SQL>edit
DECLARE v_countryid locations.country_id%TYPE :=‘CA‘; v_loc_id locations.location_id%TYPE; v_counter NUMBER(2) := 1; v_new_city locations.city%TYPE := ‘Montreal‘; BEGIN SELECT MAX(location_id) INTO v_loc_id FROM locations WHERE country_id =v_countryid; WHILE v_counter <= 3 -- 使用WHILE,当v_counter小于等于3时就执行下面的语句 LOOP INSERT INTOlocations(location_id, city, country_id) VALUES((v_loc_id +v_counter), v_new_city, v_countryid); v_counter := v_counter+ 1; END LOOP; -- 没有循环出口EXIT,当v_counter大于3时会自动退出循环 COMMIT; END; /
SQL>/
PL/SQL procedure successfully completed.
SQL>select location_id, city, country_id from locations where country_id = ‘CA‘;
LOCATION_ID CITY CO
----------- ------------------------------ --
1800 Toronto CA
1900 Whitehorse CA
1901 Montreal CA
1902 Montreal CA
1903 Montreal CA
1904 Montreal CA
1905 Montreal CA
1906 Montreal CA
8 rows selected.
-- 又多了三条记录
如果条件一次都不满足,WHILE循环会出现一次都不执行的情况。
三、FOR循环
FOR循环的基本格式为:
FORcounter IN [REVERSE]
-- REVERSE是关键字,表示反过来循环,如从10到1进行循环
lower_bound..upper_bound LOOP
--分别是下边界和上边界,变量counter和上下边界都必须是数值型
statement1;
statement2;
...
ENDLOOP;
FOR循环多用于循环次数已知的情况,FOR循环不需要专门声明一个变量作为计数器。它的计数器出了FOR循环之后是不可以使用的,如果一定要使用,建议还是专门声明一个计数器。和其他语言的FOR循环不同的是,用户不能自定义步长,如果想自定义步长,可以用基本循环或WHILE循环代替。
下面用FOR循环来改写之前的例子:
SQL>edit
DECLARE v_countryid locations.country_id%TYPE :=‘CA‘; v_loc_id locations.location_id%TYPE; v_new_city locations.city%TYPE := ‘Montreal‘; BEGIN SELECT MAX(location_id) INTO v_loc_id FROM locations WHERE country_id =v_countryid; FOR i IN 1..3 -- 这里的i不需要在DECLARE部分专门声明,1和3分别是这个循环的下边界和上边界 --FOR循环的步长是固定的,不能自行定义 LOOP INSERT INTOlocations(location_id, city, country_id) VALUES((v_loc_id + i),v_new_city, v_countryid); END LOOP; -- DBMS_OUTPUT.PUT_LINE(‘The counter is ‘ || i); -- 第一次执行先打开注解,用来验证计数器出了循环之后的情况。 COMMIT; END; /
SQL>/
* ERROR at line 16: ORA-06550: line 16, column 44: PLS-00201: identifier ‘I‘ must be declared ORA-06550: line 16, column 2: PL/SQL: Statement ignored -- 报错是因为计数器i没有声明,因此出了FOR循环就不能使用了。
SQL>/
PL/SQL procedure successfully completed.
SQL>select location_id, city, country_id from locations where country_id = ‘CA‘;
LOCATION_ID CITY CO ----------- ------------------------------ -- 1800 Toronto CA 1900 Whitehorse CA 1901 Montreal CA 1902 Montreal CA 1903 Montreal CA 1904 Montreal CA 1905 Montreal CA 1906 Montreal CA 1907 Montreal CA 1908 Montreal CA 1909 Montreal CA 11 rows selected. -- 又多了三条记录
FOR循环是比较受欢迎一种循环,因为它的循环次数可控,不过使用FOR循环,需要注意一些基本的规则:
A. 计数器counter只能在循环内部引用,它不需要在循环外部定义;
B. 不要为计数器counter赋值,它的赋值是自动完成的,但是可以将计数器的值赋值给其他变量;
C. 不要使用NULL值作为循环次数的下界和上界;
D. 下界和上界可以为非整数,但非整数会被自动计算为整数;
E. 加了关键字REVERSE之后表示循环的次数为倒序,即从上界向下界执行,但是即使使用了REVERSE,下界的值仍然应该比上界的值小,下面举个例子来演示REVERSE的用法:
SQL> edit
BEGIN DBMS_OUTPUT.PUT_LINE(‘--------Normal--------‘); FORi IN 1..3 -- 正常顺序 LOOP DBMS_OUTPUT.PUT_LINE(‘Outputis ‘ || i); ENDLOOP; DBMS_OUTPUT.PUT_LINE(‘------Reverse-------‘); FORi IN REVERSE 1..3 -- 加了关键字REVERSE会逆序执行 LOOP DBMS_OUTPUT.PUT_LINE(‘Outputis ‘ || i); END LOOP; DBMS_OUTPUT.PUT_LINE(‘-----Upperand Lower------‘); FORi IN REVERSE 3..1 -- 虽然使用了REVERSE关键字,但是下边界比上边界大,会出现不可控的现象 LOOP DBMS_OUTPUT.PUT_LINE(‘Outputis ‘ || i); END LOOP; END; /
SQL> /
--------Normal-------- Output is 1 Output is 2 Output is 3 ------Reverse------- Output is 3 Output is 2 Output is 1 -----Upper andLower------ --这一段没有执行,因为下界大于上界,会被认为结果为FALSE,故不进循环体。 PL/SQL proceduresuccessfully completed.
四、循环种类的选择
循环种类的选择应根据实际需要,这里仅提供一些基本的建议:
1. 循环体必须至少执行一次,建议使用Basic LOOP;
2. 先对条件进行判断,以决定循环体执行0次或多次,尤其是循环次数不确定的情况,建议使用WHILE循环;
3. 循环次数已知,建议使用FOR循环。
五、循环的嵌套
循环可以嵌套,但注意嵌套的次数不要过多,最好不要超过3层;使用标签来区分代码块和循环体是个不错的编程习惯;EXIT结合标签使用,可以指定当前循环退出到哪一层循环,下面来看一个小例子:
六、CONTITUE关键字
CONTITUE是ORACLE11g中引入的概念,如果数据库的版本是11g以前的,则不能用CONTINUE。
CONTITUE的用法为:
1. 跳过当前语句,但不退出循环,直接进入下一轮循环;
2. 它的句法和EXIT一样,可以使用
a. CONTINUE;
-- 不附加条件
b.CONTINUE WHEN condition;
--附加条件
c.CONTINUE label;
-- 跳转到某一个标签
在11g以前如果要实现CONTINUE的功能,需要写更为复杂的程序,引入CONTINUE可以的简化程序,提高性能。下面来看一个CONTINUE的例子:
SQL>edit
DECLARE v_total SIMPLE_INTEGER :=0; BEGIN FOR i IN 1..10 LOOP v_total := v_total + i; DBMS_OUTPUT.PUT_LINE(‘Total is: ‘ || v_total); CONTINUE WHEN i > 5; --当i大于5使,跳出当前这一轮循环,进入下一轮循环 v_total := v_total + i; DBMS_OUTPUT.PUT_LINE(‘Out of Loop Total is‘ || v_total); END LOOP; END; /
SQL>/
Total is: 1 Out of Loop Total is2 Total is: 4 Out of Loop Total is6 Total is: 9 Out of Loop Total is12 Total is: 16 Out of Loop Total is20 Total is: 25 Out of Loop Total is30 -- i 大于5时跳出当前这一轮循环 Total is: 36 Total is: 43 Total is: 51 Total is: 60 Total is: 70 PL/SQL procedure successfully completed.
再来看一个CONTINUE和标签结合使用的例子:
SQL>edit
DECLARE v_total NUMBER := 0; BEGIN <<BeforeTopLoop>> FOR i IN 1..10 LOOP v_total := v_total+ 1; DBMS_OUTPUT.PUT_LINE(‘---BeforeTopLoop---Total is: ‘ || v_total); FOR j IN 1..10 LOOP CONTINUE BeforeTopLoop WHEN i + j > 5; -- 跳转到标签BeforeTopLoop处 v_total :=v_total + 1; DBMS_OUTPUT.PUT_LINE(‘---AfterTopLoop---Total is: ‘ || v_total); END LOOP; END LOOP; END;
SQL>/
---BeforeTopLoop---Total is: 1 ---AfterTopLoop---Total is: 2 ---AfterTopLoop---Total is: 3 ---AfterTopLoop---Total is: 4 ---AfterTopLoop---Total is: 5 ---BeforeTopLoop---Total is: 6 ---AfterTopLoop---Total is: 7 ---AfterTopLoop---Total is: 8 ---AfterTopLoop---Total is: 9 ---BeforeTopLoop---Total is: 10 ---AfterTopLoop---Total is: 11 ---AfterTopLoop---Total is: 12 ---BeforeTopLoop---Total is: 13 ---AfterTopLoop---Total is: 14 ---BeforeTopLoop---Total is: 15 ---BeforeTopLoop---Total is: 16 ---BeforeTopLoop---Total is: 17 ---BeforeTopLoop---Total is: 18 ---BeforeTopLoop---Total is: 19 ---BeforeTopLoop---Total is: 20 PL/SQL procedure successfully completed.
再来看一个使用CONTINUE从内层循环跳转到外层循环的例子:
SQL>edit
BEGIN <<outer>> FOR i IN 1..5 LOOP DBMS_OUTPUT.PUT_LINE(‘Outer index = ‘|| TO_CHAR(i)); <<inner>> FOR j IN 1..5 LOOP DBMS_OUTPUT.PUT_LINE(‘--->Inner index = ‘ || TO_CHAR(j)); -- 这条语句不会执行5次,因为每次执行后就会跳出这一层循环 CONTINUE outer; END LOOP inner; END LOOP outer; END;
SQL>/
Outer index = 1 --->Inner index = 1 Outer index = 2 --->Inner index = 1 Outer index = 3 --->Inner index = 1 Outer index = 4 --->Inner index = 1 Outer index = 5 --->Inner index = 1 PL/SQL procedure successfully completed.
六、GOTO 语句
CONTINUE加上标签一起使用,和GOTO语句比较相似。GOTO语句可以无条件跳转到另一个代码块,但该代码块必须和跳转前的代码块处于同一可执行的section(如BEGIN或EXCEPTION部分)中。在实际编程中不建议使用GOTO,因为它不需要条件控制,容易破坏程序的可读性。
下面来看一个GOTO语句的例子:
SQL>edit
BEGIN GOTO second_output; --直接跳转到标签所在的位置,下面这条语句永远都不是执行 DBMS_OUTPUT.PUT_LINE(‘This linewill never execute.‘); <<second_output>> DBMS_OUTPUT.PUT_LINE(‘We arehere!‘); END; /
SQL>/
We are here! PL/SQL procedure successfully completed.
GOTO语句使用时最好加上IF语句设定跳转的条件。
本文出自 “重剑无锋 大巧不工” 博客,请务必保留此出处http://wuyelan.blog.51cto.com/6118147/1545958