总的目录和进度,请参见开始读 Oracle PL/SQL Programming 第6版
本章介绍两种类型的 PL/SQL 控制语句:条件控制语句和顺序控制语句。 几乎您编写的每一段代码都需要条件控制,即根据条件指导程序执行流程的能力。 您可以使用 IF-THEN-ELSE 和 CASE 语句来执行此操作。 还有CASE表达式; 虽然与 CASE 语句不同,但它们有时可用于完全消除对 IF 或 CASE 语句的需要。 极少情况下,您需要告诉 PL/SQL 通过 GOTO 语句无条件转移控制,或者通过 NULL 语句显式地不执行任何操作。
IF 语句允许您在程序中实现条件分支逻辑。
IF 语句有三种形式,如下表所示。
IF 类型 | 特征 |
---|---|
IF THEN END IF; |
这是 IF 语句的最简单形式。 IF 和 THEN 之间的条件决定是否执行 THEN 和 END IF 之间的语句集。 如果条件的计算结果为 FALSE 或 NULL,则不执行代码。 |
IF THEN ELSE END IF; |
这种组合实现了非此即彼的逻辑:根据 IF 和 THEN 关键字之间的条件,执行 THEN 和 ELSE 之间或 ELSE 和 END IF 之间的代码。 执行这两部分可执行语句之一。 |
IF THEN ELSIF ELSE END IF; |
IF 语句的最后一种也是最复杂的形式从一系列互斥条件中选择一个为 TRUE 的条件,然后执行与该条件关联的语句集。 这种情况应该考虑使用搜索 CASE 语句。 |
IF-THEN 语法的一般格式如下:
IF 条件
THEN
... 代码 ...
END IF;
条件为TRUE则执行代码,条件也可能为FALSE或NULL。
二值逻辑指布尔逻辑,即只提供真和假;三值逻辑除真假外,还提供一个不确定值,NULL,例如:
2 < NULL
要了解有关三值逻辑的更多信息,我推荐 Lex de Haan 和 Jonathan Gennick 的 Oracle 杂志文章“Nulls:Nothing to Worry About”。 您可能会发现 C. J. Date 的书《Database in Depth: Relational Theory for the Practitioner》也很有帮助。
使用 IS NULL 和 IS NOT NULL 等运算符或 COALESCE 和 NVL2 等函数是检测和处理潜在 NULL 值的好方法。 对于您编写的每个布尔表达式中引用的每个变量,请务必仔细考虑该变量为 NULL 时的后果。
格式方面,充分利用缩进和格式,使 IF 语句的逻辑易于理解。 未来的维护程序员会感谢你的。
当您想要在两个互斥的操作之间进行选择时,请使用 IF-THEN-ELSE 格式。
IF condition
THEN
... TRUE 可执行语句序列 ...
ELSE
... FALSE/NULL 可执行语句序列 ...
END IF;
需要记住的重要一点是,两个语句序列之一将始终执行,因为 IF-THEN-ELSE 是一个非此即彼的结构。
通常,使用布尔变量作为标志很方便,这样您就不需要多次计算相同的布尔表达式。 执行此操作时,请记住布尔表达式的结果可以直接分配给布尔变量。
即,下面的语句:
IF 表达式
...
可以用以下替代,好处我理解是可以打印值,方便调试:
boolean_variable = 表达式;
IF boolean_variable
...
IF 条件1
THEN
语句1
ELSIF 条件2
THEN
语句2
[ELSE
语句N]
END IF;
IF-THEN-ELSIF通常应该用CASE替代。注意ELSIF后面必须跟THEN,只有ELSE后面不需要THEN
IF-ELSIF中的条件,按顺序评估。如果有多个条件TRUE(应尽量避免),则先满足的会被执行,余下的不会评估。
对于复杂的逻辑,嵌套IF通常是必要的,但要小心,因为其难以理解和调试。
嵌套IF的好处是,只有外层的IF为TRUE是,内层的IF才会评估。
捷径评估是指不必评估IF语句中的所有表达式。例如逻辑AND和逻辑OR。
IF 条件1 AND 条件2
THEN
...
ELSE
...
END IF;
当条件1
为FALSE或NULL时,PL/SQL可以停止对表达式的求值,因为只有当表达式的结果为TRUE时才执行THEN分支,并且这需要两个操作数都为TRUE。一旦发现一个操作数不是TRUE,则不再有机会执行THEN分支。
注意,捷径评估仅适用于IF表达式,但对于赋值语句则不适用。
例如:
my_boolean := 条件1 AND 条件2
如果条件1
为NULL,则仍会继续评估条件2。因为此时my_boolean 的值取决于条件2。若条件2为NULL,则my_boolean 为NULL,若条件2为FALSE,则my_boolean 为FALSE。
关于这点,详见文章Nulls: Nothing to Worry About中的图1。
捷径评估也适用于CASE语句和CASE表达式。
CASE语句包括简单CASE和搜索CASE两类。CASE语句外,还有CASE表达式。
在PL/SQL的范畴,前面布尔表达式的赋值可以有TRUE,FALSE和NULL。而放在关系型数据库的范畴,三值逻辑中只有TRUE,FASLE和UNKNOWN。例如SQL的WHERE条件和CHECK约束。NULL和UNKNOWN是不同的。
先评估expression,根据结果再判断执行哪一分支。
CASE expression
WHEN result1 THEN
statements1
WHEN result2 THEN
statements2
...
ELSE
statements_else
END CASE;
ELSE部分是可选的。但你没有写ELSE时,PL/SQL会隐式替换为以下:
ELSE
RAISE CASE_NOT_FOUND;
这和IF是不一样的,IF不会报错。
这里要注意的关键点是,前面的语法图中显示的表达式(expression)和结果元素(result*#n*)可以是标量值,也可以是计算结果为标量值的表达式。例如:
CASE TRUE
...
WHEN A > 200 AND ...
为了避免 CASE_NOT_FOUND 错误,请确保不会存在任何条件都不满足的情况。
搜索的 CASE 语句计算布尔表达式列表,当它找到计算结果为 TRUE 的表达式时,执行与该表达式关联的语句序列。
CASE
WHEN expression1 THEN
statements1
WHEN expression2 THEN
statements2
...
ELSE
statements_else
END CASE;
与简单的 CASE 语句一样,适用以下规则:
注意:由于 WHEN 子句是按顺序求值的,因此您可以通过首先列出最可能的 WHEN 子句来提高代码的效率。 此外,如果您的 WHEN 子句包含“昂贵”的表达式(例如,需要大量 CPU 和内存),您可能需要将它们列在最后,以尽量减少它们被评估的机会。
CASE 语句可以像 IF 语句一样嵌套。
CASE
WHEN ...
CASE
WHEN ...
...
END CASE;
...
END CASE;
CASE 表达式对于表达式的作用与 CASE 语句对于语句的作用相同。 简单的 CASE 表达式允许您根据作为输入提供的标量值选择要计算的表达式。 搜索的 CASE 表达式对表达式列表进行计算,以找到第一个计算结果为 TRUE 的表达式,然后返回关联表达式的结果。
CASE 表达式有以下两种形式:
Simple_Case_Expression :=
CASE expression
WHEN result1 THEN
result_expression1
WHEN result2 THEN
result_expression2
...
ELSE
result_expression_else
END;
Searched_Case_Expression :=
CASE
WHEN expression1 THEN
result_expression1
WHEN expression2 THEN
result_expression2
...
ELSE
result_expression_else
END;
CASE 表达式返回单个值,即选择的 result_expression 的结果。 每个 WHEN 子句必须与一个表达式(无语句)关联。 不要使用分号或 END CASE 来标记 CASE 表达式的结束。 CASE 表达式由简单的 END 终止。
其实有点像look-up table。
与 CASE 语句不同,如果在 CASE 表达式中未选择 WHEN 子句,则不会引发错误。 相反,当不满足 WHEN 条件时,CASE 表达式将返回 NULL。
GOTO 语句执行无条件分支到 PL/SQL 块的同一执行部分中的另一个可执行语句。 与该语言中的其他结构一样,如果您正确且谨慎地使用 GOTO,您的程序将会变得更加强大。
GOTO 语句的一般格式是:
GOTO 标签名称;
其中 label_name 是标识目标语句的标签名称。 这个GOTO标签在程序中定义如下:
<<标签名称>>
GOTO 语句有几个限制:
由于 PL/SQL 提供了如此多不同的控制结构和模块化技术,因此您几乎总能找到比 GOTO 更好的方法来完成某些任务。我不建议用。
在某些情况下,您希望 PL/SQL 不执行任何操作,此时 可用NULL 语句:
NULL;
NULL使用场景,包括: