这两个 PostgreSQL 函数是否等价? (RETURNS TABLE 和 RETURNS SETOF)
Are these two PostgreSQL functions equivalent? (RETURNS TABLE and RETURNS SETOF)
我同时处理两个 PostgreSQL 安装:我的本地环境和真正的远程服务器。遗憾的是服务器有一个旧版本 (8.3.11) 而我的本地环境是较新的 (9.4)。
我目前没有办法更新远程服务器,所以我正在将一个在 9.4 中运行良好的函数(它使用 RETURNS TABLE
)转换为一个在 8.3 中应该没问题的函数。 11(应该使用 RETURNS SETOF
)。
但是,虽然本地环境功能运行良好并提供了良好的结果,但远程环境功能始终没有产生任何结果(使用完全相同的表!)
那么,这两个是完全等价的吗?
本地环境的新功能:
CREATE OR REPLACE FUNCTION pra2.GetGamesOnDate(date)
RETURNS TABLE (game_date date, is_home varchar, is_away varchar) AS $$
BEGIN
RETURN QUERY
SELECT g.game_date, p1.team_name AS plays_at_home, p2.team_name AS plays_away
FROM pra2.game g
JOIN pra2.team p1 ON g.is_home = p1.team_id
JOIN pra2.team p2 ON g.is_away = p2.team_id
WHERE g.game_date = ;
IF NOT FOUND THEN
RAISE EXCEPTION 'No hay partidos para la fecha %.', ;
END IF;
RETURN;
END
$$
LANGUAGE plpgsql;
这里是我修改后使用的函数 SETOF
CREATE TYPE return_type AS
(game_date date,
is_home varchar,
is_away varchar);
CREATE OR REPLACE FUNCTION pra2.GetGamesOnDate(date)
RETURNS SETOF return_type AS $$
DECLARE
_rec return_type;
BEGIN
RETURN QUERY
SELECT g.game_date, p1.team_name AS plays_at_home, p2.team_name AS plays_away
FROM pra2.game g
JOIN pra2.team p1 ON g.is_home = p1.team_id
JOIN pra2.team p2 ON g.is_away = p2.team_id
WHERE g.game_date = ;
IF NOT FOUND THEN
RAISE EXCEPTION 'No hay partidos para la fecha %.', ;
END IF;
RETURN next _rec;
END
$$
LANGUAGE plpgsql;
它根本没有给出任何错误消息,它运行正常,但它只是没有产生任何结果(它总是引发异常消息),所以我想知道是否在 SETOF
中设置了错误的东西查询 ...
从文档来看,RETURN QUERY
在 PostgreSQL 8.3 中没有设置 FOUND
。 (PostgreSQL 9.1 的相关文档位于 http://www.postgresql.org/docs/9.1/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-DIAGNOSTICS; the corresponding statement does not appear in the corresponding PostgreSQL 8.3 documentation at http://www.postgresql.org/docs/8.3/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-DIAGNOSTICS。)所以您的 IF NOT FOUND
检查没有按照您的意愿进行。
老实说,我不确定在 PostgreSQL 8.3 中实现此目的的最佳方法是什么。一种选择是这样写:
CREATE OR REPLACE FUNCTION pra2.GetGamesOnDate(date)
RETURNS SETOF return_type AS $$
DECLARE _rec return_type;
has_rec boolean;
BEGIN
has_rec := false;
FOR _rec IN
SELECT g.game_date, p1.team_name AS plays_at_home, p2.team_name AS plays_away
FROM pra2.game g
JOIN pra2.team p1 ON g.is_home = p1.team_id
JOIN pra2.team p2 ON g.is_away = p2.team_id
WHERE g.game_date =
LOOP
has_rec := true;
RETURN NEXT _rec;
END LOOP;
IF NOT has_rec THEN
RAISE EXCEPTION 'No hay partidos para la fecha %.', ;
END IF;
END
$$ LANGUAGE plpgsql;
(免责声明:未经测试。)
PL/pgSQL does not set the special variable FOUND
for RETURN QUERY
in PostgreSQL 8.3, yet. That was added with Postgres 8.4.
但您仍然不必求助于更复杂和昂贵的循环。您可以使用另一种方法 GET DIAGNOSTICS _ct = ROW_COUNT;
,在手册中 FOUND
旁边有解释:
CREATE TYPE return_type AS ( ...);
CREATE OR REPLACE FUNCTION pra2.GetGamesOnDate(date)
RETURNS SETOF return_type AS
$func$
DECLARE
_ct int;
BEGIN
RETURN QUERY
SELECT g.game_date, p1.team_name, p2.team_name
FROM pra2.game g
JOIN pra2.team p1 ON g.is_home = p1.team_id
JOIN pra2.team p2 ON g.is_away = p2.team_id
WHERE g.game_date = ;
GET DIAGNOSTICS _ct = ROW_COUNT; -- number of returned rows.
IF _ct = 0 THEN
RAISE EXCEPTION 'No hay partidos para la fecha %.', ;
END IF;
END
$func$ LANGUAGE plpgsql;
此外,您的变量 _rec return_type
和 RETURN next _rec;
在您的原始版本中没有任何作用。
现在功能是等价的。您甚至可以在 Postgres 9.4 中使用相同的方法。
密切相关的答案:
- Query returning exact number of rows
旁白:像 GetGamesOnDate
这样的驼峰式标识符在 Postgres 中不是一个好主意。坚持使用合法的小写名称。
我同时处理两个 PostgreSQL 安装:我的本地环境和真正的远程服务器。遗憾的是服务器有一个旧版本 (8.3.11) 而我的本地环境是较新的 (9.4)。
我目前没有办法更新远程服务器,所以我正在将一个在 9.4 中运行良好的函数(它使用 RETURNS TABLE
)转换为一个在 8.3 中应该没问题的函数。 11(应该使用 RETURNS SETOF
)。
但是,虽然本地环境功能运行良好并提供了良好的结果,但远程环境功能始终没有产生任何结果(使用完全相同的表!)
那么,这两个是完全等价的吗?
本地环境的新功能:
CREATE OR REPLACE FUNCTION pra2.GetGamesOnDate(date)
RETURNS TABLE (game_date date, is_home varchar, is_away varchar) AS $$
BEGIN
RETURN QUERY
SELECT g.game_date, p1.team_name AS plays_at_home, p2.team_name AS plays_away
FROM pra2.game g
JOIN pra2.team p1 ON g.is_home = p1.team_id
JOIN pra2.team p2 ON g.is_away = p2.team_id
WHERE g.game_date = ;
IF NOT FOUND THEN
RAISE EXCEPTION 'No hay partidos para la fecha %.', ;
END IF;
RETURN;
END
$$
LANGUAGE plpgsql;
这里是我修改后使用的函数 SETOF
CREATE TYPE return_type AS
(game_date date,
is_home varchar,
is_away varchar);
CREATE OR REPLACE FUNCTION pra2.GetGamesOnDate(date)
RETURNS SETOF return_type AS $$
DECLARE
_rec return_type;
BEGIN
RETURN QUERY
SELECT g.game_date, p1.team_name AS plays_at_home, p2.team_name AS plays_away
FROM pra2.game g
JOIN pra2.team p1 ON g.is_home = p1.team_id
JOIN pra2.team p2 ON g.is_away = p2.team_id
WHERE g.game_date = ;
IF NOT FOUND THEN
RAISE EXCEPTION 'No hay partidos para la fecha %.', ;
END IF;
RETURN next _rec;
END
$$
LANGUAGE plpgsql;
它根本没有给出任何错误消息,它运行正常,但它只是没有产生任何结果(它总是引发异常消息),所以我想知道是否在 SETOF
中设置了错误的东西查询 ...
从文档来看,RETURN QUERY
在 PostgreSQL 8.3 中没有设置 FOUND
。 (PostgreSQL 9.1 的相关文档位于 http://www.postgresql.org/docs/9.1/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-DIAGNOSTICS; the corresponding statement does not appear in the corresponding PostgreSQL 8.3 documentation at http://www.postgresql.org/docs/8.3/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-DIAGNOSTICS。)所以您的 IF NOT FOUND
检查没有按照您的意愿进行。
老实说,我不确定在 PostgreSQL 8.3 中实现此目的的最佳方法是什么。一种选择是这样写:
CREATE OR REPLACE FUNCTION pra2.GetGamesOnDate(date)
RETURNS SETOF return_type AS $$
DECLARE _rec return_type;
has_rec boolean;
BEGIN
has_rec := false;
FOR _rec IN
SELECT g.game_date, p1.team_name AS plays_at_home, p2.team_name AS plays_away
FROM pra2.game g
JOIN pra2.team p1 ON g.is_home = p1.team_id
JOIN pra2.team p2 ON g.is_away = p2.team_id
WHERE g.game_date =
LOOP
has_rec := true;
RETURN NEXT _rec;
END LOOP;
IF NOT has_rec THEN
RAISE EXCEPTION 'No hay partidos para la fecha %.', ;
END IF;
END
$$ LANGUAGE plpgsql;
(免责声明:未经测试。)
PL/pgSQL does not set the special variable FOUND
for RETURN QUERY
in PostgreSQL 8.3, yet. That was added with Postgres 8.4.
但您仍然不必求助于更复杂和昂贵的循环。您可以使用另一种方法 GET DIAGNOSTICS _ct = ROW_COUNT;
,在手册中 FOUND
旁边有解释:
CREATE TYPE return_type AS ( ...);
CREATE OR REPLACE FUNCTION pra2.GetGamesOnDate(date)
RETURNS SETOF return_type AS
$func$
DECLARE
_ct int;
BEGIN
RETURN QUERY
SELECT g.game_date, p1.team_name, p2.team_name
FROM pra2.game g
JOIN pra2.team p1 ON g.is_home = p1.team_id
JOIN pra2.team p2 ON g.is_away = p2.team_id
WHERE g.game_date = ;
GET DIAGNOSTICS _ct = ROW_COUNT; -- number of returned rows.
IF _ct = 0 THEN
RAISE EXCEPTION 'No hay partidos para la fecha %.', ;
END IF;
END
$func$ LANGUAGE plpgsql;
此外,您的变量 _rec return_type
和 RETURN next _rec;
在您的原始版本中没有任何作用。
现在功能是等价的。您甚至可以在 Postgres 9.4 中使用相同的方法。
密切相关的答案:
- Query returning exact number of rows
旁白:像 这样的驼峰式标识符在 Postgres 中不是一个好主意。坚持使用合法的小写名称。GetGamesOnDate