Postgresql - plpgsql - Control Structures

本文内容均翻译自官方文档

https://www.postgresql.org/docs/10/static/plpgsql-control-structures.html#PLPGSQL-STATEMENTS-RETURNING

========================================================

1. IF-THEN

是使用IF最简单的形式,如果条件为真,则执行,否则跳过。

Example:

IF v_user_id <> 0 THEN

UPDATE users SET email = v_email WHERE user_id = v_user_id;

END IF;

2. IF-THEN-ELSE

它允许指定一组备选语句,如果条件不为真,则应该执行这些语句。(注意,这包括条件为空的情况)。

Example:

IF parentid IS NULL OR parentid = ''

THEN

RETURN fullname;

ELSE

RETURN hp_true_filename(parentid) || '/' || fullname;

END IF;

3. IF-THEN-ELSIF

有时有两个以上的选择。IF-T-ELSIF提供了一种方便的检查几种替代方案的方法。对IF条件进行连续测试直到找到第一个IF条件为止。然后执行关联的语句,之后控制在结束if之后传递给下一个语句。(任何后续的if条件未被测试)如果没有IF条件是真的,则执行另一个块(如果有的话)。

IF boolean-expression THEN

statements

[ ELSIF boolean-expression THEN

statements

[ ELSIF boolean-expression THEN

statements

...]]

[ ELSE

statements ]

END IF;

4. CASE

简单的CASE形式提供了基于操作数相等的条件执行。搜索表达式被计算(一次),并依次与WHEN子句中的每个表达式进行比较。如果找到匹配,则执行相应的语句,然后控制传递到END CASE之后的下一个语句。如果没有找到匹配,则执行ELSE语句;但是如果不存在ELSE,则引发CASE_NOT_FOUND异常。

CASE search-expression

WHEN expression [, expression [ ... ]] THEN

statements

[ WHEN expression [, expression [ ... ]] THEN

statements

... ]

[ ELSE

statements ]

END CASE;

5. Searched CASE

CASE的搜索形式基于布尔表达式的真实性提供有条件的执行。每个子句的布尔表达式依次进行评估,直到找到一个正确的表达式。然后执行相应的语句,然后控制在结束情况后传递给下一个语句。(当表达式未被计算时)。如果没有找到真正的结果,则执行ELSE语句;但是如果不存在其他语句,则引发一个CaseSoNoSyDebug异常。

CASE

WHEN boolean-expression THEN

statements

[ WHEN boolean-expression THEN

statements

... ]

[ ELSE

statements ]

END CASE;

1. LOOP

循环定义一个无条件循环,该循环无限期地重复,直到退出或返回语句终止为止。嵌套循环中的EXIT和CONTINUE语句可以使用可选的标签来指定这些语句引用哪个循环。

[ <<label>> ]

LOOP

statements

END LOOP [ label ];

2. EXIT

如果没有给出标签,则最内层循环被终止,接下来执行结束语句循环语句。如果给出标签,它必须是嵌套循环或块的当前或某个外部级别的标签。然后,终止循环或块,并在循环/块的相应端之后继续进行语句控制。

如果指定了,则只有在布尔表达式为真时才出现循环退出。否则,控件传递到退出后的语句。

退出可用于所有类型的循环;它不限于使用无条件循环。

当与开始块一起使用时,Exchange将控件传递给块结束后的下一个语句。注意,必须为此使用标签;未标记的退出永远不会被认为与开始块匹配。(这是PostgreSQL的前8个版本的更改,这将允许未标记的退出与开始块匹配)。

EXIT [ label ] [ WHEN boolean-expression ];

Examples:

LOOP

-- some computations

IF count > 0 THEN

EXIT; -- exit loop

END IF;

END LOOP;

LOOP

-- some computations

EXIT WHEN count > 0; -- same result as previous example

END LOOP;

<<ablock>>

BEGIN

-- some computations

IF stocks > 100000 THEN

EXIT ablock; -- causes exit from the BEGIN block

END IF;

-- computations here will be skipped when stocks > 100000

END;

3. CONTINUE

如果没有给出标签,最内层循环的下一次迭代就开始了。也就是说,跳过循环主体中剩余的所有语句,并且控制返回到循环控制表达式(如果有的话)以确定是否需要另一个循环迭代。如果存在标签,则它指定将继续执行的循环的标签。

如果指定了,则只在布尔表达式为真时才开始循环的下一次迭代。否则,控件在继续后传递给语句。

继续可用于所有类型的循环;它不限于使用无条件循环。

CONTINUE [ label ] [ WHEN boolean-expression ];

Examples:

LOOP

-- some computations

EXIT WHEN count > 100;

CONTINUE WHEN count < 50;

-- some computations for count IN [50 .. 100]

END LOOP;

4. WHILE

只要布尔表达式求值为true,while语句就重复一系列语句。在循环体的每个条目之前检查表达式。

[ <<label>> ]

WHILE boolean-expression LOOP

statements

END LOOP [ label ];

Example:

WHILE amount_owed > 0 AND gift_certificate_balance > 0 LOOP

-- some computations here

END LOOP;

WHILE NOT done LOOP

-- some computations here

END LOOP;

5. FOR (Integer Variant)

这种形式的FOR创建一个遍历整数值范围的循环。变量名自动定义为类型整数,并且只存在于循环中(在循环中忽略变量名的任何现有定义)。两个表达式给出下限和上界的范围时,一旦进入循环进行评估。如果BY子句没有指定,迭代步骤是1,否则它是BY子句中指定的值,在循环条目中再次计算一次。如果指定反向,则在每次迭代之后减去步骤值,而不是添加。

[ <<label>> ]

FOR name IN [ REVERSE ] expression .. expression [ BY expression ] LOOP

statements

END LOOP [ label ];

Examples

FOR i IN 1..10 LOOP

-- i will take on the values 1,2,3,4,5,6,7,8,9,10 within the loop

END LOOP;

FOR i IN REVERSE 10..1 LOOP

-- i will take on the values 10,9,8,7,6,5,4,3,2,1 within the loop

END LOOP;

FOR i IN REVERSE 10..1 BY 2 LOOP

-- i will take on the values 10,8,6,4,2 within the loop

END LOOP;

1. Looping Through Query Results

如果循环由EXIT语句终止,则最后一个分配的行值仍然可以在循环之后访问。

此类FOR语句中使用的查询可以是向调用者返回行的任何SQL命令:SELECT是最常见的情况,但是您也可以使用INSERT、UPDATE或DELETE以及RETURNING子句。一些实用命令,如解释也会起作用。

[ <<label>> ]

FOR target IN query LOOP

statements

END LOOP [ label ];

[ <<label>> ]

FOR target IN EXECUTE text_expression [ USING expression [, ... ] ] LOOP

statements

END LOOP [ label ];

这与前面的表单类似,只是查询结果被指定为字符串表达式,在FOR循环的每个条目上计算并重新命名该表达式。这允许程序员选择预先计划的查询的速度或动态查询的灵活性,就像使用普通的EXECUTE语句一样。与执行一样,参数值可以通过使用方式插入到动态命令中。

2. Looping Through Arrays

FOREACH循环非常类似于FOR循环,但是它不是遍历SQL查询返回的行,而是遍历数组值的元素。(通常,FOREACH用于循环复合值表达式的组件;将来可以添加除数组之外的用于循环复合的变体。)

[ <<label>> ]

FOREACH target [ SLICE number ] IN ARRAY expression LOOP

statements

END LOOP [ label ];

如果没有SLICE,或者如果指定了SLICE 0,循环迭代通过计算表达式生成的数组的各个元素。目标变量按顺序分配每个元素值,并且为每个元素执行循环体。

不管数组维数的多少,都以存储顺序访问元素。虽然目标通常只是单个变量,但是当循环遍历复合值(记录)数组时,它可以是变量列表。在这种情况下,对于每个数组元素,变量是从复合值的连续列分配的。

使用正向切片值,FOREACH迭代数组的切片而不是单个元素。切片值必须是不大于数组维数的整数常量。目标变量必须是数组,并且它接收数组值的连续切片,其中每个切片具有SLICE指定的维度数。这里是一个迭代通过一维切片的例子:

3. Trapping Errors

默认情况下,在PL/pgSQL函数中发生的任何错误都会中止该函数的执行,实际上也会中止周围事务的执行。通过使用带有异常子句的开始块,可以捕获错误并从中恢复错误。

[ <<label>> ]

[ DECLARE

declarations ]

BEGIN

statements

EXCEPTION

WHEN condition [ OR condition ... ] THEN

handler_statements

[ WHEN condition [ OR condition ... ] THEN

handler_statements

... ]

END;

如果没有发生错误,则这种形式的块仅执行所有语句,然后控制传递到END之后的下一个语句。但是,如果在语句中发生错误,则放弃对语句的进一步处理,并将控制传递给EXCEPTION列表。在列表中搜索与发生的错误匹配的第一条件。如果找到匹配项,则执行相应的handler_statements,然后控制在结束后传递到下一个语句。如果没有找到匹配,错误就传播出去,好像EXCEPTION子句根本不存在:错误可以由带有EXCEPTION的封闭块捕获,或者如果没有,则中断函数的处理。

条件名称可以是附录A中显示的任何一个。类别名称匹配其类别内的任何错误。除了QUERY_CANCELED和ASSERT_FAILURE之外,其他条件都匹配其他错误类型。(可以通过名称捕获这两种错误类型是可能的,但往往不明智。)条件名称不是区分大小写的。此外,错误条件可以由SQLSTATE代码指定。

如果在所选的handler_statements中发生新错误,则此EXCEPTION子句无法捕获该错误,但会传播出去。周围的例外条款可以抓住它。

当EXCEPTION子句捕获错误时,PL/pgSQL函数的本地变量与发生错误时保持原样,但是回滚块中对持久数据库状态的所有更改。

异常处理程序经常需要识别发生的特定错误。有两种方法可以获得关于PL/pgSQL中当前异常的信息:特殊变量和GET STACKED DIAGNOSTICS命令。

在异常处理程序中,特殊变量SQLSTATE包含与引发的异常对应的错误代码(可能的错误代码列表参见表A.1)。特殊变量SqLSRM包含与异常相关联的错误消息。这些变量在异常处理程序之外是未定义的。

在异常处理程序中,还可以通过使用GET STACKED DIAGNOSTICS命令检索关于当前异常的信息。

每个项是一个关键字,标识要分配给指定变量(它应该是接收该变量的正确数据类型)的状态值。

Error Diagnostics Items

Name

Type

Description

RETURNED_SQLSTATE

text

the SQLSTATE error code of the exception

COLUMN_NAME

text

the name of the column related to exception

CONSTRAINT_NAME

text

the name of the constraint related to exception

PG_DATATYPE_NAME

text

the name of the data type related to exception

MESSAGE_TEXT

text

the text of the exception's primary message

TABLE_NAME

text

the name of the table related to exception

SCHEMA_NAME

text

the name of the schema related to exception

PG_EXCEPTION_DETAIL

text

the text of the exception's detail message, if any

PG_EXCEPTION_HINT

text

the text of the exception's hint message, if any

PG_EXCEPTION_CONTEXT

text

line(s) of text describing the call stack at the time of the exception

4. Obtaining Execution Location Information

GET DIAGNOSTICS命令检索关于当前执行状态的信息。它的PG_CONTEXT状态项对于识别当前执行位置是有用的。PG_CONTEXT返回一个文本字符串,其中包含描述调用堆栈的文本行。第一行是指当前函数,当前正在执行GET DIAGNOSTICS 命令。第二个和任何后续行引用调用栈上的调用函数。

GET STACKED DIAGNOSTICS ... PG_EXCEPTION_CONTEXT 返回相同类型的堆栈跟踪,但是描述检测到错误的位置,而不是当前位置。

猜你喜欢

转载自blog.csdn.net/chuckchen1222/article/details/82352131
今日推荐