英文:
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) 如果你只需要返回一个查询结果,你可以使用SETOF
和RETURN QUERY
1b) 或者只使用语言SQL
,像@ClodoaldoNeto一样,它会使用SQL的SELECT
语句原生地返回一个查询结果
- 如果你需要在过程中处理结果,你必须使用
SETOF
和RETURN 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
- If you need to process the result in the procedure, you must use
SETOF
andRETURN NEXT
, ensuring you checkIF FOUND THEN RETURN;
(note lack ofNEXT
, 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论