pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
控制结构可能是PL/pgSQL中最有用(也最重要)的 部分。借助PL/pgSQL的控制结构,你可以以非常 灵活而强大的方式操纵PostgreSQL数据。
RETURN expression;
函数终止,expression的值会被返回给 上层执行器。表达式的结果会被自动转换成函数的返回类型, 转换方式与赋值中描述的相同。
函数的返回值不能没有定义。如果控制到达函数顶层块的末尾而 没有碰到 RETURN 语句,就会发生运行时错误。
IF语句让你可以基于某些条件执行命令。 PL/pgSQL有四种 IF 形式:IF-THEN、 IF-THEN-ELSE、IF-THEN-ELSE IF 和 IF-THEN-ELSIF-THEN-ELSE。
IFboolean-expressionTHENstatementsEND IF;
IF-THEN 语句是 IF 的最简单形式。如果条件为真,THEN 和 END IF 之间的语句会被执行。否则,它们会被跳过。
IF v_user_id <> 0 THEN
UPDATE users SET email = v_email WHERE user_id = v_user_id;
END IF;
IFboolean-expressionTHENstatementsELSEstatementsEND IF;
IF-THEN-ELSE 语句在 IF-THEN 的基础上增加了一种能力:你可以 指定一组在条件求值为 FALSE 时执行的备选语句。
IF parentid IS NULL or parentid = ''''
THEN
return fullname;
ELSE
return hp_true_filename(parentid) || ''/'' || fullname;
END IF;
IF v_count > 0 THEN
INSERT INTO users_count(count) VALUES(v_count);
return ''t'';
ELSE
return ''f'';
END IF;
IF 语句可以嵌套,如下面的例子所示:
IF demo_row.sex = ''m'' THEN
pretty_sex := ''man'';
ELSE
IF demo_row.sex = ''f'' THEN
pretty_sex := ''woman'';
END IF;
END IF;
使用这种形式时,你实际上是把一个 IF 语句嵌套在外层 IF 语句 的 ELSE 部分中。因此每个嵌套的 IF 都需要一个 END IF 语句, 外层的 IF-ELSE 也需要一个。这是可行的,但当要检查的备选 分支很多时就会变得乏味。
IFboolean-expressionTHENstatements[ ELSIFboolean-expressionTHENstatements[ ELSIFboolean-expressionTHENstatements...]] [ ELSEstatements] END IF;
IF-THEN-ELSIF-ELSE 提供了一种在一条语句中检查多个备选分支的 更方便的方法。形式上它等价于嵌套的 IF-THEN-ELSE-IF-THEN 命令,但只需要一个 END IF。
下面是一个例子:
IF number = 0 THEN
result := ''zero'';
ELSIF number > 0 THEN
result := ''positive'';
ELSIF number < 0 THEN
result := ''negative'';
ELSE
-- hmm, the only other possibility is that number IS NULL
result := ''NULL'';
END IF;
最后的 ELSE 部分是可选的。
使用 LOOP、EXIT、WHILE 和 FOR 语句,你可以让你的 PL/pgSQL函数重复执行一系列命令。
[<<label>>]
LOOP
statements
END LOOP;
LOOP 定义一个无条件循环,它会无限重复,直到被 EXIT 或 RETURN 语句终止。可选的标签可以被嵌套循环中的 EXIT 语句 用来指定应该终止哪一层嵌套。
EXIT [label] [ WHENexpression];
如果没有给出label,最内层的循环 会被终止,接下来执行 END LOOP 之后的语句。如果给出了 label,它必须是当前循环或嵌套 循环/块的某个外层的标签。此时被命名的循环或块被终止, 控制转移到该循环/块对应的 END 之后的语句。
如果出现了 WHEN,只有当指定条件为真时循环才会退出,否则 控制传递到 EXIT 之后的语句。
例子:
LOOP
-- some computations
IF count > 0 THEN
EXIT; -- exit loop
END IF;
END LOOP;
LOOP
-- some computations
EXIT WHEN count > 0;
END LOOP;
BEGIN
-- some computations
IF stocks > 100000 THEN
EXIT; -- illegal. Can't use EXIT outside of a LOOP
END IF;
END;
[<<label>>] WHILEexpressionLOOPstatementsEND LOOP;
WHILE 语句在条件表达式求值为真期间重复执行一系列语句。 条件在每次进入循环体之前被检查。
例如:
WHILE amount_owed > 0 AND gift_certificate_balance > 0 LOOP
-- some computations here
END LOOP;
WHILE NOT boolean_expression LOOP
-- some computations here
END LOOP;
[<<label>>] FORnameIN [ REVERSE ]expression..expressionLOOPstatementsEND LOOP;
这种形式的 FOR 创建一个遍历一段整数值范围的循环。变量 name被自动定义为 integer 类型并且 只存在于循环内部。给出范围下界和上界的两个表达式在进入 循环时被求值一次。迭代步长通常是 1,但指定 REVERSE 时 是 -1。
整数 FOR 循环的一些例子:
FOR i IN 1..10 LOOP
-- some expressions here
RAISE NOTICE ''i is %'',i;
END LOOP;
FOR i IN REVERSE 10..1 LOOP
-- some expressions here
END LOOP;
使用另一种类型的 FOR 循环,你可以遍历一个查询的结果并相应地 操纵这些数据。语法是:
[<<label>>] FORrecord | rowINselect_queryLOOPstatementsEND LOOP;
记录或行变量会被依次赋以 SELECT 查询产生的所有行,并且 循环体对每一行都会执行。下面是一个例子:
CREATE FUNCTION cs_refresh_mviews () RETURNS INTEGER AS '
DECLARE
mviews RECORD;
BEGIN
PERFORM cs_log(''Refreshing materialized views...'');
FOR mviews IN SELECT * FROM cs_materialized_views ORDER BY sort_key LOOP
-- Now "mviews" has one record from cs_materialized_views
PERFORM cs_log(''Refreshing materialized view '' || quote_ident(mviews.mv_name) || ''...'');
EXECUTE ''TRUNCATE TABLE '' || quote_ident(mviews.mv_name);
EXECUTE ''INSERT INTO '' || quote_ident(mviews.mv_name) || '' '' || mviews.mv_query;
END LOOP;
PERFORM cs_log(''Done refreshing materialized views.'');
RETURN 1;
end;
' LANGUAGE 'plpgsql';
如果循环被 EXIT 语句终止,最后赋值的行在循环之后仍然 可以访问。
FOR-IN-EXECUTE 语句是在记录上迭代的另一种方式:
[<<label>>] FORrecord | rowIN EXECUTEtext_expressionLOOPstatementsEND LOOP;
它与前一种形式类似,区别在于源 SELECT 语句被指定为一个 字符串表达式,该表达式在每次进入 FOR 循环时被求值并重新 制定计划。这样程序员就可以像使用普通 EXECUTE 语句那样, 在预计划查询的速度和动态查询的灵活性之间做出选择。
PL/pgSQL解析器目前通过检查 FOR 后面提到的 目标变量是否已被声明为记录/行变量来区分两种 FOR 循环 (整数型或返回记录型)。如果不是,它就被认为是整数 FOR 循环。当真正的问题比如说只是 FOR 变量名拼写错误时,这会 导致相当不直观的错误消息。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。