Oracle学习之三 程序控制结构

时间:2022-09-08 18:00:35

1.条件控制

1.1 IF语句

if语句由于根据条件,执行两个代码块之一。其语法形式如下:

IF 条件1 THEN        。。。     ELSEIF 条件2 THEN       。。。    ELSE       。。。    END IF; 

这里,elseif和else块时可选的。当使用条件分支语句时,不仅可以使用if语句进行简单条件判断,而且还可以使用if语句进行二重分支和多重分支判断。

1.2 CASE语句和CASE表达式

使用CASE语句处理多重条件分支有两种方法:使用单一选择符进行等值比较;使用多种条件进行非等值比较。

1) 在CASE语句中使用单一选择符进行等值比较

当使用CASE语句进行多重条件分支时,如果条件选择符完全相同,并且条件表达式为相同条件选择,那么可以选择使用单一选择符进行等值比较。

CASE selector     WHEN exp1  THEN state1;     WHEN exp2  THEN state2;     ....     [else stateN;] END CASE; 

这里,selector用于指定条件选择符,exp用于指定条件值的表达式,state用于指定要执行的条件操作。如果设置的所有条件都不满足,就会执行else语句,为避免CASE_NOT_FOUND异常,在编写CASE语句时应该带有else子句。

2) 在CASE语句中使用多种条件比较

如果包含有多种条件进行不等比较,那么必须在WHEN子句中指定比较条件。

CASEWHEN condition1 THEN state1;     WHEN condition2 THEN state2;     ....     [else stateN;] END CASE; 

condition用于指定不同的比较条件。

3) CASE表达式

CASE表达式也可以采用上面两种形式。

case_experssion := CASE exp  WHEN。。。

或者

case_experssion := CASE  WHEN。。。

 

2.循环控制

2.1 基本循环

基本循环语句以LOOP开始,END LOOP 结束。

LOOP     statement;     ...     EXIT [WHEN condition];     END LOOP; 

当使用基本循环时,无论是否满足条件,语句至少会执行一次。当条件为true时,会退出循环,并执行end LOOP后的相应操作。注意,当编写基本循环时,一定要包含exit语句,否则PL/SQL块会陷入死循环;另外还应该定义循环控制变量,并且在循环体内修改循环控制的值。

2.2 WHILE循环

只有条件为true时,才执行循环体内的内容,while循环以while…LOOP 开始,以end  LOOP结束。

2.3 FOR循环

当使用基本循环或者while循环时,需要定义循环控制变量,并且循环控制变量不仅可以是NUMBER类型,也可以使用其他数据类型;而当使用for循环时,会隐含定义循环控制变量

FOR counter IN [REVERSE] lower_bound ..upper_bound LOOP statement; ... end loop; 

counter是循环控制变量,该变量由Oracle隐含定义,不需要显式定义;lower_bound和upper_bound分别对应于循环控制变量的上下界值。默认情况下,当使用FOR循环时,每次循环时循环控制变量会自动加1,如果指定了reverse选项,则每次循环控制变量自动减1.

2.4嵌套循环和标号

嵌套循环是指在一个循环语句中嵌入另一个循环语句,而标号(Lable)则用于标记嵌套块或者嵌套循环。通过在嵌套循环中使用标号,可以区分内层和外层循环,并且可以在内层循环中直接退出外层循环。可以使用<>定义标号。

3.顺序控制

PL/SQL不仅提供了条件分支语句和循环控制语句,还提供了顺序控制语句GOTO和NULL。但是,在一般情况下尽量不要使用goto和null语句。

3.1 GOTO语句

GOTO语句用于跳转到指定标号处去执行语句。注意,因为使用GOTO语句会增加程序的复杂性,并且使得应用程序可读性变差,所以开发应用程序时,一般不建议使用GOTO语句。

其语法形式为:

GOTO label_name; 

其中,label_name是已经定义的标号名,需要注意的是,标号后至少要包含一条可执行语句。

3.2 NULL语句

NULL语句不会执行任何操作,并且会直接将控制传递到下一条语句。使用NULL语句的好处时可以提高程序的可读性。

 

4.异常处理

PL/SQL语言中,任何类型的错误将被看作为不应该在程序中发生的异常情况。异常可以是以下之一:

☆ 由系统产生的错误(例如内存不足,重复索引值)

☆ 由用户行为导致的错误

☆ 由应用程序发出给用户的警告

PL/SQL使用一种异常处理器来捕获和响应这些错误。当发生错误时,不管是系统错误还是应用程序错误都会抛出一个异常。此时,当前PL/SQL块执行部分的处理就会中止,程序流程就会转到当前块的异常处理部分来处理异常。在完成异常处理后,程序不能返回到执行部分。

通常,异常分为两种类型:系统异常和程序员自定义的异常。

1) 系统异常

系统异常时由Oracle自己定义的,通常时由PL/SQL运行时引擎在检测了错误时抛出的。

系统异常不需要我们定义,在应用程序运行时会自动抛出,然后交给我们编写异常处理部分进行异常处理。

表4-1 Oracle预定义异常

异常名

对应错误号

说明

ACCESS_INTO_NULL ORA-06530 当开发对象类型应用时,在引用对象属性之前,必须先初始化对象。如果没有初始化,直接为对象属性赋值则会抛出异常。
CASE_NOT_FOUND ORA-06592 在CASE语句中,WHEN子句中没有包含必须的条件分支,且没有ELSE语句。
COLLECTION_IS_NULL ORA-06531 在给集合元素赋值前,必须首先初始化集合元素。
CURSOR_ALREADY_OPEN ORA-06511 当重新打开已经打开的游标时抛出异常
DUP_VAL_INDEX ORA-00001 在唯一索引对应的列上键入重复值时抛出异常
INVALID_CURSOR ORA-01001 当试图在不合法的游标上执行操作时抛出
INVALID_NULBER ORA-01722 当内嵌sql语句不能呢个有效地将字符转换为数字时抛出
NO_DATA_FOUND ORA-01403 当执行select into 未返回行,或者引用了索引表未初始化元素时抛出
TOO_MANY_ROWS ORA-01422 当执行select into 语句时,如果返回超过一行抛出
ZERO_DIVIDE ORA-01476 除数为0时抛出
SUBSCRIPT-BEYOND-COUNT ORA-06533 当使用嵌套表或者VARRAY元素时,如果元素下标超过了范围则抛出
SUBSCRIPT_OUTSIDE_LIMIT ORA-06532 当使用嵌套表或者VARRAY元素时,如果元素下标为负数抛出
VALUE_ERROR ORA-06502 执行赋值操作时,如果变量长度不足以容纳实际数据时抛出
LOGIN_BENIED ORA-01017 应用程序需要连接到Oracle数据库时,如果提供了错误的用户名或口令时抛出
NOT_LOGGED_ON ORA-01012 如果应用程序没有连接到Oracle数据库时抛出
PROGRAM_ERROR ORA-06501 如果出现该错误说明PL/SQL内部存在问题,可能需要重装数据字典
ROWTYPE_MISMATCH ORA-06504 当执行赋值操作时,如果宿主游标变量和PL/SQL游标变量的返回类型不兼容时抛出
SELF_IS_NULL ORA-30625 当使用对象类型时,如果在NULL实例上调用成员方法时抛出
STORAGE_ERROR ORA-06500 如果超出内存空间或者内存被损坏时抛出
SYS_INVALID_ROWID ORA-01410 将字符串转换为rowid时,必须使用有效的字符串,否则抛出异常
TIMEOUT_ON_RESOURCE ORA-00051 如果Oracle等待资源时出现超时错误时抛出

2)自定义异常

异常处理的流程包括定义异常、抛出异常和处理异常三个部分。

4.1 定义异常

在异常被抛出或处理之前,必须先定义。系统异常已经由Oracle本身定义了,因此我们在应用程序中不需要定义它们。我们可以使用两种不同的方式来自定义异常。

① 定义命名的异常

为了处理异常,必须对有一个该异常的名称。通过在EXCEPTION关键字前列出我们想在程序中抛出的异常的名称,就可以定义一个异常。

异常的名称只能以两种方式被引用:

☆ 在要跑出异常的程序执行部分用RAISE语句引用

☆  在要处理抛出的异常的异常处理部分的WHEN子句中引用。

②将异常名称与错误号关联

EXCEPTION_INIT命令用于将一个内部错误号与异常的名称关联。关联完成后,就可以通过名称抛出异常,并编写一个显式的WHEN处理器捕获异常。

EXCEPTION_INIT必须出现在块的定义部分,并且异常的名字必须在相同的块或者包规范中已经定义了。

DECLARE        异常名称  EXCEPTION;        PRAGMA EXCEPTION_INIT(异常名称,错误号); 

这里,错误号是一个整数,他有如下的限制:

☆  不能是-1403 (这个错误号时给NO_DATA_FOUND的)

☆  不能是0或者任何除100以外的正数。

☆  不能时小于-10000000的负数。

4.2 抛出异常

在应用程序中抛出异常的方式有三种:

☆  当Oracle检测到错误时会自动抛出异常;

☆  程序员可以使用RAISE语句抛出异常;

☆  程序员可以使用RAISE_APPLICATION_ERROR内置函数抛出异常。

1)RAISE语句抛出异常

使用RAISE语句可以抛出自定义异常或系统异常。

RAISE 异常名称;

2)RAISE_APPLICATION_ERROR语句抛出异常

使用RAISE_APPLICATION_ERROR替代RAISE的优点在于,我们可以将错误消息与异常关联起来。注意,该过程只能在数据库端的子程序(过程、函数、包、触发器)中使用,而不能在匿名块和客户端的子程序中使用。

RAISE_APPLICATION_ERROR(错误号,错误描述 [,{true|false} ]); 

其中,错误号必须是-20000到-20999之间的负整数;错误描述长度不能超过2048字节;第三个参数为可选参数,如果设置为true,则该错误号被放在先前的错误堆栈中;如果设置为false(默认值),则会替代先前所有错误。

4.3处理异常

一旦异常被抛出,当前PL/SQL块就会停止正常执行,将控制权交给异常处理部分。为了处理抛出的异常,必须在异常处理部分编写异常处理器。异常处理器必须出现在执行部分之后,在END语句之前。EXception关键字指示了异常处理部分和异常处理器的开始。

异常只有在抛出的异常匹配WHEN子句中的异常名时才会被处理。这里WHEN子句之后只能跟异常名,不能跟错误号。