循環是指在程序中重複執行一條或多條語句、PL/SQL中的循環主要有三種:sql
1.Basic Loop數據庫
2. FORLoop編程
3.WHILE Loopide
下面來逐一介紹這三種循環的用法。oop
1、BasicLoops性能
基本循環的格式以下:spa
LOOPorm
statement1;blog
...ci
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 -- 執行了循環語句後,多了三條記錄
2、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循環會出現一次都不執行的狀況。
3、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.
4、循環種類的選擇
循環種類的選擇應根據實際須要,這裏僅提供一些基本的建議:
1. 循環體必須至少執行一次,建議使用Basic LOOP;
2. 先對條件進行判斷,以決定循環體執行0次或屢次,尤爲是循環次數不肯定的狀況,建議使用WHILE循環;
3. 循環次數已知,建議使用FOR循環。
5、循環的嵌套
循環能夠嵌套,但注意嵌套的次數不要過多,最好不要超過3層;使用標籤來區分代碼塊和循環體是個不錯的編程習慣;EXIT結合標籤使用,能夠指定當前循環退出到哪一層循環,下面來看一個小例子:
6、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.
6、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語句設定跳轉的條件。