KingbaseES PL/SQL 过程语言参考手册(5. 控制语句)

5. 控制语句

PL/SQL有三类控制语句:条件选择语句、循环语句和顺序控制语句。

PL/SQL 控制语句的类别有: - 条件选择语句,针对不同的数据值运行不同的语句。

条件选择语句是 IF语句 和 CASE语句。

  • 循环语句,它使用一系列不同的数据值运行相同的语句。

    循环语句是基本的 LOOP语句、FOR LOOP语句 和 WHILE LOOP语句。

    EXIT 语句将控制转移到循环结束。 CONTINUE 语句退出循环的当前迭代并将控制转移到下一个迭代。 EXIT 和 CONTINUE 都有一个可选的 WHEN 子句,您可以在其中指定一个条件。

  • 顺序控制语句,这对于 PL/SQL 编程并不重要。

    顺序控制语句是转到指定语句的 GOTO 语句和不执行任何操作的 NULL语句。

5.1. 条件选择语句

条件选择语句 IF 和 CASE 针对不同的数据值运行不同的语句。

IF 语句根据条件运行或跳过一个或多个语句。 IF 语句有以下形式:

  • IF THEN

  • IF THEN ELSE

  • IF THEN ELSIF

CASE 语句从一系列条件中进行选择,并运行相应的语句。 CASE 语句有以下形式:

  • 简单 CASE 语句,它计算单个表达式并将其与几个值进行比较。

  • 搜索 CASE 语句,它计算多个条件并选择第一个为真的条件。

当要对每个备选方案采取不同的操作时,CASE 语句更适用。

5.1.1. IF THEN 语句

IF THEN 语句根据条件运行或跳过一个或多个语句。

IF THEN 语句具有以下结构:

IF condition THEN
  statements
END IF;

如果condition为真,则statements运行;否则,statements不运行。

有关完整的语法,请参阅“ IF 语句”。

示例 5-1 IF THEN 语句

在此示例中,当且仅当 a 大于 b 时,打印 a - b 的值。

\set SQLTERM /
DECLARE
        PROCEDURE p(a int, b int) AS
        BEGIN
                IF a > b THEN
                        RAISE NOTICE 'a - b = %', a - b;
                END IF;
        END;
BEGIN
        p(1,2);
        p(3,2);
END;
/

结果:

NOTICE:  a - b = 1

5.1.2. IF THEN ELSE 语句

IF THEN ELSE 语句具有以下结构:

IF condition THEN
  statements
ELSE
  else_statements
END IF;

如果条件的值为真,则 statements 运行; 否则, else_statements 运行。

IF 语句可以嵌套,如例 5-3 所示。

有关完整的语法,请参阅“ IF 语句”。

示例 5-2 IF THEN ELSE 语句

在这个例子中,当 a 大于 b 时,打印 a - b 的值,当 a 小于等于 b 时,打印 a + b 的值。

\set SQLTERM /
DECLARE
        PROCEDURE p(a int, b int) AS
        BEGIN
                IF a > b THEN
                        RAISE NOTICE 'a - b = %', a - b;
                ELSE
                        RAISE NOTICE 'a + b = %', a + b;
                END IF;
        END;
BEGIN
        p(1, 2);
        p(3, 2);
END;
/

结果:

NOTICE:  a + b = 3
NOTICE:  a - b = 1

示例 5-3 嵌套的 IF THEN ELSE 语句

\set SQLTERM /
DECLARE
        PROCEDURE p(a int, b int) AS
        BEGIN
                IF a > b THEN
                        RAISE NOTICE 'a - b = %', a - b;
                ELSE
                        IF a = b THEN
                                RAISE NOTICE 'a = b';
                        ELSE
                                RAISE NOTICE 'a + b = %', a + b;
                        END IF;
                END IF;
        END;
BEGIN
        p(1, 2);
        p(2, 2);
        p(3, 2);
END;
/

结果:

NOTICE:  a + b = 3
NOTICE:  a = b
NOTICE:  a - b = 1

5.1.3. IF THEN ELSIF 语句

IF THEN ELSIF语句具有以下结构:

IF condition_1 THEN
  statements_1
ELSIF condition_2 THEN
  statements_2
[ ELSIF condition_3 THEN
        statements_3
]...
[ ELSE
        else_statements
]
END IF;

IF THEN ELSIF 语句运行条件为真的第一条语句,不计算剩余条件。如果没有条件为真,则运行 else_statements(如果存在); 否则,IF THEN ELSIF 语句什么也不执行。

单个 IF THEN ELSIF 语句比逻辑等效的嵌套 IF THEN ELSE 语句更容易理解:

-- IF THEN ELSIF statement

IF condition_1 THEN statements_1;
  ELSIF condition_2 THEN statements_2;
  ELSIF condition_3 THEN statement_3;
END IF;

-- Logically equivalent nested IF THEN ELSE statements

IF condition_1 THEN
  statements_1;
ELSE
  IF condition_2 THEN
        statements_2;
  ELSE
        IF condition_3 THEN
          statements_3;
        END IF;
  END IF;
END IF;

有关完整的语法,请参阅“ IF 语句”。

示例 5-4 IF THEN ELSIF 语句

在本例中,使用 ELSIF 达到了和嵌套 IF THEN ELSE 同样的功能。

\set SQLTERM /
DECLARE
        PROCEDURE p(a int, b int) AS
        BEGIN
                IF a > b THEN
                        RAISE NOTICE 'a - b = %', a - b;
                ELSIF a = b THEN
                        RAISE NOTICE 'a = b';
                ELSE
                        RAISE NOTICE 'a + b = %', a + b;
                END IF;
        END;
BEGIN
        p(1, 2);
        p(2, 2);
        p(3, 2);
END;
/

结果:

NOTICE:  a + b = 3
NOTICE:  a = b
NOTICE:  a - b = 1

示例 5-5 IF THEN ELSIF 语句模拟简单的 CASE 语句

此示例使用带有许多 ELSIF 子句的 IF THEN ELSIF 语句将单个值与许多可能值进行比较。 相对比而言,一个简单的 CASE 语句更清晰——见例 5-6。

\set SQLTERM /
DECLARE
  grade CHAR(1);
BEGIN
  grade := 'A';

  IF grade = 'A' THEN
        RAISE NOTICE 'Excellent';
  ELSIF grade = 'B' THEN
        RAISE NOTICE 'Very Good';
  ELSIF grade = 'C' THEN
        RAISE NOTICE 'Good';
  ELSIF grade = 'D' THEN
        RAISE NOTICE 'Fair';
  ELSIF grade = 'F' THEN
        RAISE NOTICE 'Poor';
  ELSE
        RAISE NOTICE 'No such grade';
  END IF;
END;
/

结果:

NOTICE:  Excellent

5.1.4. 简单 CASE 语句

简单CASE语句具有以下结构:

CASE selector
WHEN selector_value_1 THEN statements_1
WHEN selector_value_2 THEN statements_2
...
WHEN selector_value_n THEN statements_n
[ ELSE
  else_statements ]
END CASE;]

selector 是一个表达式(通常是单个变量)。 每个 selector_value 可以是文字或表达式。 (对于完整的语法,请参阅“ CASE 语句”。)

简单 CASE 语句运行 selector_value 等于 selector 的第一条语句,不计算剩余条件。如果没有 selector_value 等于 selector,则 CASE 语句如果存在 else_statements 则运行,否则引发预定义的异常 CASE_NOT_FOUND。

示例 5-6 使用一个简单的 CASE 语句将单个值与多个可能值进行比较。 示例 5-6 中的 CASE 语句在逻辑上等价于示例 5-5 中的 IF THEN ELSIF 语句。

注意

如果简单 CASE 语句中的 selector 的值为 NULL,则它不能被 WHEN NULL 匹配(参见:ref:示例 3-50)。 相反,请使用带有 WHEN 条件 IS NULL 的搜索 CASE 语句(参见示例 3-53)。

示例 5-6 简单的 CASE 语句

\set SQLTERM /
DECLARE
  grade CHAR(1);
BEGIN
  grade := 'B';

  CASE grade
        WHEN 'A' THEN RAISE NOTICE 'Excellent';
        WHEN 'B' THEN RAISE NOTICE 'Very Good';
        WHEN 'C' THEN RAISE NOTICE 'Good';
        WHEN 'D' THEN RAISE NOTICE 'Fair';
        WHEN 'F' THEN RAISE NOTICE 'Poor';
        ELSE RAISE NOTICE 'No such grade';
  END CASE;
END;
/

结果:

NOTICE:  Very Good

5.1.5. 搜索 CASE 语句

搜索CASE语句具有以下结构:

CASE
WHEN condition_1 THEN statements_1
WHEN condition_2 THEN statements_2
...
WHEN condition_n THEN statements_n
[ ELSE
  else_statements ]
END CASE;]

搜索 CASE 语句运行条件为真的第一条语句。不计算剩余条件。如果没有条件为真, 则 CASE 语句如果存在 else_statements 则运行 ,否则引发预定义的异常 CASE_NOT_FOUND。(对于完整的语法,请参阅“ CASE 语句”。)

示例 5-7 中的搜索CASE语句在逻辑上等价于 示例 5-6 中的简单CASE语句。

在 示例 5-7 和 示例 5-6 中,ELSE子句都可以替换为EXCEPTION。示例 5-8`在逻辑上等价于:ref:`示例 5-7。

示例 5-7 搜索 CASE 语句

DECLARE
  grade CHAR(1);
BEGIN
  grade := 'B';

  CASE
        WHEN grade = 'A' THEN RAISE NOTICE 'Excellent';
        WHEN grade = 'B' THEN RAISE NOTICE 'Very Good';
        WHEN grade = 'C' THEN RAISE NOTICE 'Good';
        WHEN grade = 'D' THEN RAISE NOTICE 'Fair';
        WHEN grade = 'F' THEN RAISE NOTICE 'Poor';
        ELSE RAISE NOTICE 'No such grade';
  END CASE;
END;
/

结果:

NOTICE: Very Good

示例 5-8 CASE 语句中的 EXCEPTION 而不是 ELSE 子句

\set SQLTERM /
DECLARE
  grade CHAR(1);
BEGIN
  grade := 'B';

  CASE
        WHEN grade = 'A' THEN RAISE NOTICE 'Excellent';
        WHEN grade = 'B' THEN RAISE NOTICE 'Very Good';
        WHEN grade = 'C' THEN RAISE NOTICE 'Good';
        WHEN grade = 'D' THEN RAISE NOTICE 'Fair';
        WHEN grade = 'F' THEN RAISE NOTICE 'Poor';
  END CASE;
EXCEPTION
  WHEN CASE_NOT_FOUND THEN
        RAISE NOTICE 'No such grade';
END;
/

结果:

NOTICE:  Very Good

5.2. 循环语句

循环语句使用一系列不同的值迭代地运行相同的语句。

一个 LOOP 语句包含三个部分

  1. 一个迭代,也称为循环变量,用于将循环的值传递到循环体

  2. 迭代控件为循环生成值

  3. 为每个值执行一次循环体

loop_statement ::= [ iteration_scheme ] LOOP
                         loop_body
END LOOP [ label ];
iteration_scheme ::= WHILE expression
                                           | FOR iterator

循环语句是:

  • 基本的LOOP

  • FOR LOOP

  • 游标FOR LOOP

  • WHILE LOOP

退出循环的语句是:

  • EXIT

  • EXIT WHEN

退出当前循环迭代的语句是:

  • CONTINUE

  • CONTINUE WHEN

EXIT、EXIT WHEN、CONTINUE 和 CONTINUE WHEN 可以出现在循环内的任何位置,但不能出现在循环外。建议使用这些语句而不是 GOTO 语句,它可以通过将控制转移到循环外的语句来退出循环或循环的当前迭代。

引发的异常也会退出循环。

LOOP 语句可以被标记,LOOP 语句可以嵌套。 建议为嵌套循环使用标签以提高可读性。 您必须确保 END LOOP 语句中的标签与同一循环语句开头的标签匹配(编译器不检查)。

另请参阅

  • :ref:` GOTO 语句`

  • :ref:` CONTINUE 语句`

  • :ref:` EXIT 语句`

  • :ref:`异常处理概述`了解有关异常的信息

  • :ref:`使用游标 FOR LOOP 语句处理查询结果集`以获取有关游标 FOR LOOP 的信息

5.2.1. 基本循环语句

基本的 LOOP 语句具有这种结构。

随着循环的每次迭代,语句运行并且控制返回到循环的顶部。 为了防止无限循环,必须通过退出循环语句或引发异常来退出循环。

[ label ] LOOP
  statements
END LOOP [ label ];

另请参阅

5.2.2. FOR LOOP 语句概述

FOR LOOP 语句为循环索引的每个值运行一个或多个语句。

FOR LOOP 头指定迭代器。迭代器指定一个迭代和迭代控件。迭代控件向迭代对象提供一系列值,以便在循环体中进行使用。循环体中有语句对迭代的每一个值进行执行。

可用的迭代控制是:

  • Stepped Range:一种迭代控件,可生成一系列步进数值。当未指定步长时,计数控制是步长为 1 的 integer 类型的步长范围。

  • 单个表达式:计算单个表达式的迭代控件。

  • 重复表达式:重复计算单个表达式的迭代控件。

  • 游标:一个迭代控件,它从游标、游标变量或动态 SQL 生成所有记录。

FOR LOOP 语句具有以下结构:

[ label ] for_loop_header
  statements
END LOOP [ label ];
for_loop_header ::= FOR iterator LOOP
iterator ::= iterand_decl [, iterand_decl] IN iteration_ctl_seq
iterand_decl  ::= pls_identifier [ MUTABLE | IMMUTABLE ] [ constrained_type ]
iteration_ctl_seq ::= qual_iteration_ctl [,]...
qual_iteration_ctl ::= [ REVERSE ] iteration_control  pred_clause_seq
iteration_control ::= stepped_control
                                          | single_expression_control
                                          | cursor_control
pred_clause_seq ::= [ stopping_pred ] [ skipping_pred ]
stopping_pred ::= WHILE boolean_expression
skipping_pred ::= WHEN boolean_expression
stepped_control ::= lower_bound .. upper_bound [ BY step ]
single_expression_control ::= [ REPEAT ] expr

5.2.2.1. FOR LOOP迭代

FOR LOOP 语句的索引或迭代数被隐式或显式声明为循环本地的变量。

循环中的语句可以读取迭代的值,但不能更改它。循环外的语句不能引用迭代。在 FOR LOOP 语句运行后,迭代数未定义。循环迭代数有时称为循环计数器。

示例 5-9 外部语句引用 FOR LOOP 语句索引

在此示例中,FOR LOOP 语句之外的语句引用了循环索引,从而导致错误。

\set SQLTERM /
BEGIN
  FOR i IN 1..3 LOOP
        RAISE NOTICE 'Inside loop, i = %', i;
  END LOOP;

  RAISE NOTICE 'Outside loop, i = %', i;
END;
/

结果:

NOTICE:  Inside loop, i = 1
NOTICE:  Inside loop, i = 2
NOTICE:  Inside loop, i = 3
ERROR:  column "i" does not exist
LINE 1: SELECT i
                           ^
QUERY:  SELECT i
CONTEXT:  PL/SQL function inline_code_block line 5 at RAISE

示例 5-10 与变量同名的 FOR LOOP 语句索引

如果 FOR LOOP 语句的索引与匿名块中声明的变量同名,则本地隐式声明会隐藏另一个声明,如本例所示。

\set SQLTERM /
DECLARE
  i NUMBER := 10;
BEGIN
  FOR i IN 1..5 LOOP
        RAISE NOTICE 'Inside loop, i = %', i;
  END LOOP;

  RAISE NOTICE 'Outside loop, i = %', i;
END;
/

结果:

NOTICE:  Inside loop, i = 1
NOTICE:  Inside loop, i = 2
NOTICE:  Inside loop, i = 3
NOTICE:  Inside loop, i = 4
NOTICE:  Inside loop, i = 5
NOTICE:  Outside loop, i = 10

示例 5-11 FOR LOOP 语句引用与索引同名的变量

这个例子展示了如何更改例 5-11 以允许循环内的语句引用匿名块中声明的变量。

CREATE OR REPLACE PROCEDURE p AS
<<main>>
DECLARE
  i NUMBER := 10;
BEGIN
  FOR i IN 1..5 LOOP
        RAISE NOTICE 'local: %, global: %',i ,main.i;
  END LOOP;
END;
/
call p();
/

结果:

NOTICE:  local: 1, global: 10
NOTICE:  local: 2, global: 10
NOTICE:  local: 3, global: 10
NOTICE:  local: 4, global: 10
NOTICE:  local: 5, global: 10

示例 5-12 具有相同索引名称的嵌套 FOR LOOP 语句

在此示例中,嵌套 FOR LOOP 语句的索引具有相同的名称。内循环通过使用外循环的标签来引用外循环的索引。 仅为了清楚起见,内部循环还使用自己的标签限定对自己索引的引用。

\set SQLTERM /
BEGIN
  <<label1>>
  FOR i IN 1..3 LOOP
        <<label2>>
        FOR i IN 1..3 LOOP
          IF label1.i = 2 THEN
                RAISE NOTICE 'lable1: i = %, label2: i = %',label1.i, label2.i;
          END IF;
        END LOOP label2;
  END LOOP label1;
END;
/

结果:

NOTICE:  lable1: i = 2, label2: i = 1
NOTICE:  lable1: i = 2, label2: i = 2
NOTICE:  lable1: i = 2, label2: i = 3

5.2.2.2. 迭代可变性

迭代的可变性属性决定了它是否可以在循环体中赋值。

如果迭代器中指定的所有迭代控件都是游标控件,则迭代默认情况下是可变的。否则,迭代是不可变的。通过在迭代变量后指定 MUTABLE 或 IMMUTABLE 关键字,可以在迭代声明中更改迭代的默认可变性属性。

声明迭代可变时的注意事项: - 对迭代控制的值的迭代或一对迭代控制的迭代控制的值的任何修改都不会影响由该迭代控制产生的值。 - 对迭代范围迭代控制或重复的单个表达式迭代控制的迭代的任何修改都可能会影响该控件的行为及其产生的值。 - 当 PL/SQL 编译器可以确定使迭代可变可能会对运行时性能产生不利影响时,它可能会报出警告。

5.2.2.3. 步进范围迭代控制

步进范围迭代控件生成一系列数值。

控制表达式是下限、上限和步长。

stepped_control ::= [ REVERSE ] lower_bound..upper_bound [ BY step ]
lower_bound ::= numeric_expression
upper_bound ::= numeric_expression
step ::= numeric_expression

将步进范围迭代控制扩展到 PL/SQL

当迭代控制初始化时,每个控制表达式都被计算并转换为迭代的类型。Step 必须具有严格的正数值。 如果在计算控制表达式时发生任何异常,则放弃循环并进行正常的异常处理。 未指定步长时,其值为 1。由步进范围迭代控制生成的值逐步从下限到上限。 当指定 REVERSE 时,值从上限逐步递减到下限。如果迭代具有浮点类型,则循环控制值的某些组合可能会因为舍入误差而创建无限循环。没有语义或动态分析会报告这一点。 当迭代是可变的并且在循环体中被修改时,修改后的值将用于下一次迭代更新中的增量和循环结束检测,这样可能会改变循环处理的值的顺序。

示例 5-13 FOR LOOP 语句范围迭代控制

在此示例中,迭代 i 的 lower_bound 为 1,upper_bound 为 3。循环打印从 1 到 3 的数字。

\set SQLTERM /
BEGIN
  FOR i IN 1..3 LOOP
         RAISE NOTICE '%',i;
  END LOOP;
END;
/

结果:

NOTICE:  1
NOTICE:  2
NOTICE:  3

示例 5-14 反向 FOR LOOP 语句范围迭代控制

此示例中的 FOR LOOP 语句打印从 3 到 1 的数字。循环变量 i 隐式声明为 PLS_INTEGER(计数和索引循环的默认值)。

\set SQLTERM /
BEGIN
   FOR i IN REVERSE 1..3 LOOP
          RAISE NOTICE '%',i;
   END LOOP;
END;
/

结果:

NOTICE:  3
NOTICE:  2
NOTICE:  1

示例 5-15 步进范围迭代控件

此示例显示一个循环变量 i,计数器的增量为2。

\set SQLTERM /
BEGIN
   FOR i IN 1 .. 10 BY 2 LOOP
          RAISE NOTICE '%',i;
   END LOOP;
END;
/

结果:

NOTICE:  1
NOTICE:  3
NOTICE:  5
NOTICE:  7
NOTICE:  9

示例 5-16 使用 FOR LOOP 步进范围迭代器的简单步进过滤器

您可以使用步进范围迭代器来实现步进过滤器。

FOR i IN lower..upper BY k LOOP
   newcol(i) := col(i)
END LOOP;

5.2.2.4. 游标迭代控制

游标迭代控件生成由显式或隐式游标返回的 RECORD 序列。

游标定义是控制表达式。不能将 REVERSE 与游标迭代控件一起使用。

cursor_iteration__control ::=  { cursor_object
                                        | sql_statement
                                        | cursor_variable
                                        | dynamic_sql }

cursor_object 是一个显式的 PL/SQL 游标对象。 sql_statement 是为直接在迭代控件中指定的 SQL 语句创建的隐式 PL/SQL 游标对象。

cursor_variable 是一个 PL/SQL REF CURSOR 对象。在循环体中修改迭代时,对迭代控件生成的下一个值没有影响。 当游标变量遇到迭代控件时必须打开,否则会引发异常。当迭代控制用尽时,它保持打开状态。如果在执行循环体期间不是通过迭代访问游标变量,则行为未指定。

将游标迭代控制扩展到 PL/SQL

计算游标以创建迭代向量。如果向量为空,则迭代控制已用尽。在向量中获取一个值来为迭代创建下一个值。 计算任何停止谓词。如果它的值不为 TRUE,则迭代控制已用尽。 计算任何跳过的谓词。如果它的值不为 TRUE,则跳过下一步。 计算循环体,对获取的每个迭代值重复相同的操作,直到迭代控制用尽。

示例 5-17 游标迭代控件

此示例创建 id 到表 t 中数据的关联数组映射。

OPEN c FOR SELECT * FROM T1;
FOR r IN c LOOP
   RAISE NOTICE 'r = %',r;
END LOOP;
CLOSE c;

5.2.2.5. 在迭代控制中使用动态 SQL

...
dynamic_sql ::= EXECUTE dynamic_sql_stmt [ using_clause ]

using_clause ::= USING [ [ IN ] (bind_argument [,])+ ]

动态 SQL 可用于游标迭代控制。如果它被用作第一个迭代控件,则必须为迭代指定显式类型(或为一对控件的值迭代指定)。 using_clause 是唯一允许的子句。不得使用 INTO 或动态返回子句。 如果指定的 SQL 语句是一种不能返回任何行的类型,则会报告运行时错误,类似于在普通 SQL 语句指定bulk collect into 或 into 子句时报告的运行时错误。

示例 5-18 使用动态 SQL 作为迭代控制

此示例显示迭代控件从动态 SQL 生成所有记录。 它打印 id 小于103的所有员工的 name 和 id。它在停止谓词为 TRUE 时停止执行循环体。

\set SQLTERM /
DECLARE
   cursor_str VARCHAR2(500) := 'SELECT name, id FROM student where id = :1 ORDER BY name';
   r record;
   i int := 1;
BEGIN
   FOR r IN EXECUTE cursor_str USING i LOOP
          raise notice 'r = %',r;
   END LOOP;
END;
/

结果:

NOTICE:  r = (xx,1)

5.2.3. WHILE LOOP 语句

WHILE LOOP 语句在条件为真时运行一个或多个语句。

它有这样的结构:

[ label ] WHILE condition LOOP
  statements
END LOOP [ label ];

如果条件为真,则语句运行并且控制返回到循环的顶部,再次计算条件。如果条件不成立,则控制转移到 WHILE LOOP 语句之后的语句。 为了防止无限循环,循环内的语句必须使条件为 false 或 null。有关完整的语法,请参阅“WHILE LOOP 语句”。

语句中的 EXIT、EXIT WHEN、CONTINUE 或 CONTINUE WHEN 会导致循环或循环的当前迭代提前结束。

某些语言具有 LOOP UNTIL 或 REPEAT UNTIL 结构,它在循环底部而不是顶部测试条件,以便语句至少运行一次。 要在 PL/SQL 中模拟这种结构,请使用带有 EXIT WHEN 语句的基本 LOOP 语句:

LOOP
  statements
  EXIT WHEN condition;
END LOOP;

5.3. 顺序控制语句

与 IF 和 LOOP 语句不同,顺序控制语句 GOTO 和 NULL 对于 PL/SQL 编程并不重要。

很少需要转到指定语句的 GOTO 语句。

NULL 语句什么都不做,可以通过明确条件语句的含义和动作来提高可读性。

5.3.1. GOTO 语句

GOTO 语句无条件地将控制转移到标签。标签在其范围内必须是唯一的,并且必须位于可执行语句或 PL/SQL 块之前。运行时,GOTO 语句将控制转移到带标签的语句或块。

对于 GOTO 语句限制,请参阅“ GOTO 语句”。

谨慎使用 GOTO 语句——过度使用它们会导致代码难以理解和维护。不要使用 GOTO 语句将控制从深度嵌套的结构转移到异常处理程序,而是通过引发异常。 有关 PL/SQL 异常处理机制的信息,请参阅PL/SQL 错误处理。 该GOTO语句将控制权转移到出现引用标签的第一个封闭块。

5.3.2. NULL 语句

NULL 语句只将控制权传递给下一条语句。一些语言将这样的指令称为无操作。

NULL 语句的一些用途是: - 为 GOTO 语句提供目标 - 通过明确条件语句的含义和动作来提高可读性 - 创建占位符和存根子程序 - 表明您意识到一种可能性,但无需采取任何行动

示例 5-19 显示无操作的 NULL 语句

NULL 语句强调90分以上的学生才会被表扬。

\set SQLTERM /
DECLARE
  id  INT = 1;
  score  NUMBER;
  name TEXT;
BEGIN
  SELECT score, name INTO score, name
  FROM student
  WHERE id = id
  LIMIT 1;

  IF score >= 90 THEN
        RAISE NOTICE '% is a good student.',name;
  ELSE
        NULL;  -- 小于90分的学生不会被表扬
  END IF;
END;
/

示例 5-20 创建子程序期间 NULL 语句作为占位符

NULL 语句让您可以编译这个子程序并在以后填充真实的主体。

\set SQLTERM /
CREATE OR REPLACE PROCEDURE p (
  id INT,
  score NUMBER
) AUTHID DEFINER AS
BEGIN    -- Executable part starts here
  NULL;  -- Placeholder
END p;
/

示例 5-21 简单 CASE 语句的 ELSE 子句中的 NULL 语句

NULL 语句表明您选择对 A、B、C、D 和 F 以外的成绩不采取任何行动。

\set SQLTERM /
CREATE OR REPLACE PROCEDURE show_grade (
  grade CHAR
) AUTHID DEFINER AS
BEGIN
  CASE grade
        WHEN 'A' THEN RAISE NOTICE 'Excellent';
        WHEN 'B' THEN RAISE NOTICE 'Very Good';
        WHEN 'C' THEN RAISE NOTICE 'Good';
        WHEN 'D' THEN RAISE NOTICE 'Fair';
        WHEN 'F' THEN RAISE NOTICE 'Poor';
        ELSE NULL;
  END CASE;
END;
/
BEGIN
  show_grade('A');
  show_grade('S');
END;
/

结果:

Excellent
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值