【问题标题】:How to return no records found from a stored procedure如何返回未从存储过程中找到的记录
【发布时间】:2014-12-18 23:31:43
【问题描述】:

当没有找到记录时,是否可以让存储过程的行为与常规选择查询完全相同,或者这是驱动程序问题。

例如,使用 go,不返回任何行的查询将返回 sql.ErrNoRows 错误。但是,这不会:

create table emptytable(id int);

create function selectany() returns emptytable as $$
DECLARE
  _out emptytable;
BEGIN
  SELECT * INTO emptytable FROM emptytable limit 1;
  RETURN _out;
END;
$$ LANGUAGE PLPGSQL;

我尝试过 SELECT INTO STRICT,虽然这会引发“查询未返回任何行”错误,但它与非存储过程查询不同。也没有提高 NO_DATA_FOUND。

【问题讨论】:

  • 定义一个SET OF函数怎么样?

标签: postgresql go plpgsql


【解决方案1】:

如果我正确理解您的要求:

从函数中返回一行或不返回,并允许对返回的行(如果有)执行更多操作。

测试表:

CREATE TABLE emptytable(id int, txt text);  -- multiple columns

返回一个或不返回一个完整的表格行

CREATE OR REPLACE FUNCTION selectany_all()
  RETURNS SETOF emptytable AS
$func$
DECLARE
   _out  emptytable;
BEGIN
   FOR _out IN
      SELECT * FROM emptytable LIMIT 1
   LOOP
     -- do something with _out before returning
     RAISE NOTICE 'before: %', _out;
     RETURN NEXT _out;
     -- or do something with _out after returning row
     RAISE NOTICE 'after: %', _out;
   END LOOP;
END
$func$ LANGUAGE plpgsql;

对于更灵活的方法:返回任意列

CREATE OR REPLACE FUNCTION selectany_any()
  RETURNS TABLE (id int, txt text) AS
$func$
BEGIN
   FOR id, txt IN
      SELECT e.id, e.txt FROM emptytable e LIMIT 1
   LOOP  
     -- do something with id and text before returning
     RAISE NOTICE 'before: %, %', id, txt;
     RETURN NEXT;
     -- or do something with id and text after returning row
     RAISE NOTICE 'after: %, %', id, txt;
   END LOOP;
END
$func$ LANGUAGE plpgsql;

注意,如果没有行,LOOP永远不会输入。因此,您不会从我的测试代码中得到NOTICE

这两个函数也适用于返回的 nLIMIT 1 仅适用于此特定请求。

密切相关,有更多解释:

【讨论】:

    【解决方案2】:

    2.5 个选项:

    1a) 如果只需要返回一个查询,可以使用SETOFRETURN QUERY

    1b) 或者只使用语言SQL 作为@ClodoaldoNeto,它使用sql 的SELECT stmt 本地返回查询

    2) 如果您需要在程序中处理结果,您必须使用SETOFRETURN NEXT,确保您检查IF FOUND THEN RETURN;(注意缺少NEXT,如果给出将充当单个空白返回行)

    理想情况下,我不想将SETOF 用于已知完全不返回或仅返回 1 行的过程,但似乎需要SETOF 才能从应用程序中获取像 sql 语句一样查询的过程并拥有驱动程序认识NO ROWS RETURNED

    以下示例:

    create table emptytable(id int);
    
    create function selectany() returns setof emptytable as $$
    DECLARE
      _out emptytable;
    BEGIN
      SELECT * INTO _out FROM emptytable limit 1;
      IF FOUND THEN
        RETURN _out;
      END IF;
      RETURN;
    END;
    $$ LANGUAGE PLPGSQL;
    
    create function selectany_rq() returns setof emptytable as $$
    BEGIN
      RETURN QUERY SELECT * INTO _out FROM emptytable limit 1;
    END;
    $$ LANGUAGE PLPGSQL;    
    

    【讨论】:

    • 只使用RETURN QUERY SELECT ...(没有INTO _out)。有很多相关的答案。 Try a search.
    • @ErwinBrandstetter 谢谢,我查看了您提供的搜索,但它忽略了需要处理查询结果的用例,在我的情况下,这是使用存储过程而不是嵌入的 sql 的主要原因该应用程序,特别是带有SETOF 声明的SELECT INTO _out ... RETURN NEXT _out 似乎工作得很好。
    • 对于你的第一个函数selectany() 我得到RETURN cannot have a parameter in function returning set。 (使用 pg 9.1 进行测试。)您的第二个函数 selectany_rq() 缺少 _out 的声明,但修复后,我仍然得到:ERROR: cannot open SELECT query as cursor。我添加了另一个答案。
    【解决方案3】:

    按照 cmets 的建议,请返回 setof emptytable

    create function selectany()
    returns setof emptytable as $$
        select *
        from emptytable 
        limit 1
        ;
    $$ language sql;
    

    普通的 sql 可以做到这一点

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-22
      • 1970-01-01
      • 2019-06-04
      • 2019-04-20
      • 2020-04-24
      • 1970-01-01
      • 2017-05-06
      相关资源
      最近更新 更多