簡體   English   中英

這兩個PostgreSQL函數是否相同? (退貨表和退貨設置)

[英]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 = $1;
   IF NOT FOUND THEN
      RAISE EXCEPTION 'No hay partidos para la fecha %.', $1;
   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 = $1;
   IF NOT FOUND THEN
   RAISE EXCEPTION 'No hay partidos para la fecha %.', $1;
   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 ;相應的語句未出現在相應的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;

(免責聲明:未經測試。)

PL / pgSQL 沒有為PostgreSQL 8.3中的RETURN QUERY設置特殊變量FOUND 這是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中使用它。

密切相關的答案:

GetGamesOnDate :像Postgres這樣的Camel案例標識符如 GetGamesOnDate 是一個壞主意。 堅持合法的小寫名稱。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM