在 PL/pgSQL 中是否有一种简单的方法来检查查询是否没有返回结果?

ice*_*fex 21 postgresql plpgsql

我目前正在尝试使用 PL/pgSQL,想知道是否有更优雅的方法来做这样的事情:

select c.data into data from doc c where c.doc_id = id and c.group_cur > group_cur order by c.id desc limit 1;
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        select c.data into data from doc c where c.doc_id = id and c.global_cur > global_cur order by c.id desc limit 1;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                RETURN NULL;
Run Code Online (Sandbox Code Playgroud)

fil*_*rem 23

异常块用于捕获错误,而不是检查条件。换句话说,如果某些条件可以在编译时处理,则不应将其捕获为错误,而是由普通程序逻辑解决。

PL/PgSQL 文档的 Trapping Errors 部分,您可以找到这样的提示:

提示:包含 EXCEPTION 子句的块比没有 EXCEPTION 子句的块进入和退出的成本要高得多。因此,不要在不需要的情况下使用 EXCEPTION。

代替使用异常(坏)或 IF/THEN/ELSIF(更好),您可以将其重写为一个查询:

SELECT c.data into data
FROM  doc c
WHERE c.doc_id = id
  and (
    c.group_cur > group_cur
    or
    c.global_cur > global_cur
  )
ORDER BY
  -- this will make group always preferred over global
  case when c.group_cur > group_cur then 1 else 2 end ASC,
  -- and this is your normal ordering
  c.id DESC
limit 1;
Run Code Online (Sandbox Code Playgroud)

如果你真的想要两个查询,你可以使用特殊的 FOUND 变量来测试上一个查询是否给出了任何结果:

select c.data into data
from doc c
where c.doc_id = id and c.group_cur > group_cur
order by c.id desc limit 1;
if not found then
    select c.data into data
    from doc c
    where c.doc_id = id and c.global_cur > global_cur
    order by c.id desc limit 1;
    if not found then return null; end if;
end if;
Run Code Online (Sandbox Code Playgroud)

强制性 RTFM 链接如下:-)

看到用于描述FOUND可变的,并且对于IF/THEN块。


ale*_*exk 16

您可以检查布尔类型的特殊变量 FOUND。从文档:

FOUND 在每个 PL/pgSQL 函数调用中以 false 开始。它由以下每种类型的语句设置:

SELECT INTO 语句将 FOUND 设置为在分配了行时为真,如果没有返回行则为假。

如果 PERFORM 语句生成(并丢弃)一行或多行,则将 FOUND 设置为 true,如果没有生成行,则设置为 false。

如果至少有一行受到影响,UPDATE、INSERT 和 DELETE 语句将 FOUND 设置为 true,如果没有行受到影响,则设置为 false。

如果 FETCH 语句返回一行,则将 FOUND 设置为 true,如果没有返回行,则设置为 false。

如果 MOVE 语句成功地重新定位游标,则将 FOUND 设置为 true,否则设置为 false。

FOR 或 FOREACH 语句在迭代一次或多次时将 FOUND 设置为 true,否则设置为 false。FOUND 在循环退出时以这种方式设置;在循环执行过程中,FOUND 不会被循环语句修改,尽管它可能会被循环体内其他语句的执行所改变。

如果查询至少返回一行,则 RETURN QUERY 和 RETURN QUERY EXECUTE 语句将 FOUND 设置为 true,如果没有返回任何行,则设置为 false。

其他 PL/pgSQL 语句不会改变 FOUND 的状态。请特别注意,EXECUTE 会更改 GET DIAGNOSTICS 的输出,但不会更改 FOUND。

FOUND 是每个 PL/pgSQL 函数中的局部变量;对它的任何更改仅影响当前功能。

  • 通常不会,只有在指定了 STRICT 子句时才会引发异常,例如 SELECT * INTO STRICT my record... (3认同)