2015-05-31 48 views
3

我正在處理兩個PostgreSQL同時安裝:我的本地環境和真正的遠程服務器。可悲的是服務器有一箇舊版本(8.3.11),我的本地環境更新(9.4)。這兩個PostgreSQL函數是否相同? (RETURNS TABLE和RETURNS SETOF)

我目前沒有更新遠程服務器的方法,因此我將一個運行良好的函數(它使用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; 

它沒有給出錯誤信息的話,那運行正常,但它不會產生任何結果(它總是會引發異常消息),所以我想知道是否在中設置了錯誤查詢...

+0

您忘了添加您提到的(逐字)錯誤消息。應該永遠在那裏。 –

回答

3

從文檔判斷,RETURN QUERY未在PostgreSQL 8.3中設置FOUND。 (PostgreSQL 9.1的相關文檔位於http://www.postgresql.org/docs/9.1/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-DIAGNOSTICS;相應的語句沒有出現在http://www.postgresql.org/docs/8.3/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-DIAGNOSTICS的相應PostgreSQL 8.3文檔中。)因此,您的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; 

(免責聲明:沒有測試)

+0

高手!它完全像你說的那樣工作!我仍然會抱怨他們正在使用8.3的事實......但至少你給了我很大的推動力。我最近纔開始學習postgreSQL,並且通過閱讀更新版本的文檔來完成它,所以這有點令人困惑。 –

1

PL/pgSQL的does not set the special variable FOUND for RETURN QUERY in PostgreSQL 8.3,但。那是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 = $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的一個壞主意。堅持合法的小寫字母名稱。

+0

感謝您的替代版本,我會記住你的建議! –