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


16

我目前正在尝试使用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;

Answers:


21

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

PL / PgSQL文档的“陷阱错误”部分中,您可以找到这样的提示:

提示:包含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;

如果您确实需要两个查询,则可以使用特殊的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;

强制性RTFM链接如下:-)

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


13

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

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

如果分配了行,则SELECT INTO语句将FOUND设置为true;如果未返回任何行,则将设置为false。

如果PERFORM语句产生(或丢弃)一行或多行,则将FOUND设置为true;如果不产生任何行,则将其设置为false。

UPDATE,INSERT和DELETE语句将FOUND设置为FOUND(如果影响至少一行),则为False(如果不影响任何行)。

如果FETCH语句返回一行,则将FOUND设置为true;如果不返回任何行,则将其设置为false。

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

如果FOR或FOREACH语句重复一次或多次,则将FOUND设置为true,否则设置为false。当循环退出时,以这种方式设置FOUND。在循环执行过程中,尽管循环主体中其他语句的执行可能会更改FOUND,但循环语句不会修改FOUND。

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

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

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


但是select into不返回任何数据的仍然会引发异常,对吗?
杰克说试试topanswers.xyz 2012年

3
通常不,它仅在指定了STRICT子句的情况下才会引发异常,例如SELECT * INTO STRICT我的记录…
alexk'1

啊,是的,我不好-尽管这并不意味着OP示例中的异常处理程序永远不会触发?:-)
杰克说试试topanswers.xyz 2012年

1
@JackDouglas:没有数据通常不会导致异常(除了上面的STRICT修饰符之类的特殊情况外)。OP在那里有一个误解。
Erwin Brandstetter,2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.