Oracle程序控制结构简介
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子句之后只能跟异常名,不能跟错误号。