设为首页 收藏本站
查看: 1434|回复: 0

[经验分享] 9.PL_SQL——PL_SQL中的循环控制语句

[复制链接]

尚未签到

发表于 2018-10-24 07:51:18 | 显示全部楼层 |阅读模式
  循环是指在程序中重复执行一条或多条语句、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_idfromlocations 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 /
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结合标签使用,可以指定当前循环退出到哪一层循环,下面来看一个小例子:
DSC0000.png

  六、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
  
      
  
      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  
        
  
        FOR i IN 1..5
  
        LOOP
  
            DBMS_OUTPUT.PUT_LINE('Outer index = '|| TO_CHAR(i));
  

  
            
  
            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.');
  
   
  
    DBMS_OUTPUT.PUT_LINE('We arehere!');
  
END;
  
/
  SQL>/
We are here!  
PL/SQL procedure successfully completed.
  GOTO语句使用时最好加上IF语句设定跳转的条件。



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-625650-1-1.html 上篇帖子: SQL的汇总统计SELECT语句 下篇帖子: MySQL server has gone away解决方法
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表