如何从存储过程中返回“未找到记录”的结果。

huangapple go评论97阅读模式
英文:

How to return no records found from a stored procedure

问题

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

例如,在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,虽然它会引发一个"query returned no rows"错误,但它与非存储过程查询不同。使用NO_DATA_FOUND也不行。

英文:

Is it possible to have a stored procedure behave exactly like a regular select query when no records are found, or is this a driver issue.

For example, with go, a query that returns no rows will return an sql.ErrNoRows error. However, this will not:

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;

I have tried SELECT INTO STRICT, and while that raises a "query returned no rows" error, it is not the same as a non-stored procedure query. Neither is raising NO_DATA_FOUND.

答案1

得分: 3

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

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

测试表:

CREATE TABLE emptytable(id int, txt text);  -- 多个列

返回一行或零行完整表行

CREATE OR REPLACE FUNCTION selectany_all()
  RETURNS SETOF emptytable AS
$func$
DECLARE
   _out  emptytable;
BEGIN
   FOR _out IN
      SELECT * FROM emptytable LIMIT 1
   LOOP
     -- 在返回之前对_out进行一些操作
     RAISE NOTICE 'before: %', _out;
     RETURN NEXT _out;
     -- 或在返回行后对_out进行一些操作
     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  
     -- 在返回之前对id和txt进行一些操作
     RAISE NOTICE 'before: %, %', id, txt;
     RETURN NEXT;
     -- 或在返回行后对id和txt进行一些操作
     RAISE NOTICE 'after: %, %', id, txt;
   END LOOP;
END
$func$ LANGUAGE plpgsql;

请注意,如果没有行,则不会进入LOOP。因此,你将不会从我的测试代码中得到任何NOTICE

这两个函数也适用于返回n行,LIMIT 1只是针对这个特定请求。

与此相关的更多解释:

英文:

If I understand your requirements correctly:

Return one or no row from a function and allow to do more with the returned row (if any).

Test table:

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

To return one or no complete table row:

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;

For a more flexible approach: return arbitrary columns:

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;

Note, the LOOP is never entered if there is no row. Accordingly you will get no NOTICE from my test code.

Both functions work for n rows returned as well, LIMIT 1 is just for this particular request.

Closely related, wtih more explanation:

答案2

得分: 2

2.5个选项:

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

1b) 或者只使用语言SQL,像@ClodoaldoNeto一样,它会使用SQL的SELECT语句原生地返回一个查询结果

  1. 如果你需要在过程中处理结果,你必须使用SETOFRETURN NEXT,确保你检查IF FOUND THEN RETURN;(注意缺少NEXT,如果给出的话,它将作为返回一个空行)

理想情况下,我不想在已知返回零行或1行的过程中使用SETOF,但似乎需要使用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;
英文:

2.5 options:

1a) If you just need to return a query, you can use SETOF and RETURN QUERY

1b) or just use language SQL as @ClodoaldoNeto, which returns a query natively using sql's SELECT stmt

  1. If you need to process the result in the procedure, you must use SETOF and RETURN NEXT, ensuring you check IF FOUND THEN RETURN; (note lack of NEXT, which if given will act as a single blank row is returned)

Ideally, I'd like to not use SETOF for procedures known to return exactly none or 1 rows, but it seems SETOF is required to get a procedure to query like an sql statement from the app and have drivers recognize NO ROWS RETURNED

Examples below:

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;    

答案3

得分: 0

根据评论中的建议,返回setof emptytable

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

普通的SQL可以实现这个功能。

英文:

As suggested in the comments do return setof emptytable

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

Plain sql can do that

huangapple
  • 本文由 发表于 2014年10月23日 18:02:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/26525705.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定