3

I am dealing with two PostgreSQL installs at the same time: My local environment and the real remote server. Sadly the server has an old version (8.3.11) and my local environment is newer (9.4).

I don't have means to update the remote server at the moment, so I am converting a function that runs well in 9.4 (it uses RETURNS TABLE) to a function that should be fine in 8.3.11 (it should use RETURNS SETOF).

But while the local environment function works well and it gives good results, the remote one always yields no result (using the very same tables!)

So, are these two fully equivalent?

Newer function for local environment:

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 = $1;
   IF NOT FOUND THEN
      RAISE EXCEPTION 'No hay partidos para la fecha %.', $1;
   END IF;
   RETURN;
END
$$
   LANGUAGE plpgsql;

And here the function I have modified to use 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 = $1;
   IF NOT FOUND THEN
   RAISE EXCEPTION 'No hay partidos para la fecha %.', $1;
   END IF;
      RETURN next _rec;
END
$$
   LANGUAGE plpgsql;

It gives no error message at all, it runs ok, but it just yields no results (it always raises the exception message), so I am wondering whether there is something wrongly set up in the SETOF query ...

4

2 回答 2

3

从文档来看,在 PostgreSQL 8.3RETURN QUERY中没有设置。FOUND(PostgreSQL 9.1 的相关文档位于http://www.postgresql.org/docs/9.1/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-DIAGNOSTICS;相应的语句未出现在相应的 PostgreSQL 8.3 文档中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 = $1
    LOOP
        has_rec := true;
        RETURN NEXT _rec;
    END LOOP;
    IF NOT has_rec THEN
        RAISE EXCEPTION 'No hay partidos para la fecha %.', $1;
    END IF;
END
$$ LANGUAGE plpgsql;

(免责声明:未经测试。)

于 2015-05-31T20:15:33.080 回答
1

PL/pgSQL尚未在 PostgreSQL 8.3 中设置特殊变量FOUNDRETURN QUERY这是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 = $1;

   GET DIAGNOSTICS _ct = ROW_COUNT;  -- number of returned rows.

   IF _ct = 0 THEN
      RAISE EXCEPTION 'No hay partidos para la fecha %.', $1;
   END IF;
END
$func$  LANGUAGE plpgsql;

此外,您的变量在原始版本_rec return_typeRETURN next _rec;没有任何用途。

现在功能是等价的。你甚至可以在 Postgres 9.4 中使用它。

密切相关的答案:

旁白:在 Postgres 中,像 Camel case 标识符GetGamesOnDate是一个坏主意。坚持使用合法的小写名称。

于 2015-06-01T01:25:16.013 回答