2012-10-24 65 views
2

在用戶定義的函數中,如何返回由加入其他表的投影形成的表?PostgreSQL 8.1中的SQL函數「RETURNS TABLE」語法錯誤

下面是一個簡單的例子

CREATE FUNCTION something123(character varying(100)) RETURNS TABLE (a integer, b character varying(300)) AS 
$$ 
    SELECT b.year, p.materialUsed FROM bestBefore b join packaged p on b.id=p.id WHERE id=$1; 
$$ 
LANGUAGE SQL 
; 

它總是在餐桌上的錯誤。你將如何獲得該選擇語句的內容返回?

我使用Postgres的8.1.21

+1

答案更新以反映版本。特別是當使用真正古老的PostgreSQL 8.1版本(2005年11月發佈,2010年11月最終更新)時,請在所有問題中明確提及您的版本。 –

+0

@CraigRinger我應該使用 select version();在Postgres或psql - 版本在終端?他們爲什麼不同呢? – Celeritas

+0

他們當然是不同的。在大多數系統中,它們會產生相同的結果,但'SELECT version()'產生* server *版本,而'psql --version'則打印'psql'客戶端的版本。完全可以使用(比如說)psql 9.2連接到PostgreSQL 8.4,所以版本不一定相同。對於大多數問題,這是你關心的服務器版本,這就是爲什麼'select version()'是首選的。有些系統(通常是Mac OS X)通常會在其上安裝多個PostgreSQL版本,因此瞭解它是服務器版本可能很重要。 –

回答

4

你的代碼是好的,但你的PostgreSQL的版本是沒有的。它不支持RETURNS TABLE,根據the PostgreSQL 8.1 documentation for CREATE FUNCTION

在像8.1這樣極其陳舊的PostgreSQL版本中,您必須聲明RETURNS SETOF RECORD而不使用RETURNS TABLE,因爲它不支持該舊版本。 RETURNS SETOF RECORD導致該函數返回一個匿名記錄集。然後,您必須在調用點指定記錄結構,像這樣:

regress=# CREATE FUNCTION something123_legacy(character varying(100)) 
RETURNS SETOF RECORD AS 
$$ 
    SELECT 1, 'fred'::varchar(300); 
$$ 
LANGUAGE SQL; 

regress=# SELECT * FROM something123_legacy('blah') somethingresult(col1name integer, col2name character varying(300)); 
col1name | col2name 
----------+---------- 
     1 | fred 
(1 row) 

或者,你可以CREATE TYPE創建一個定義行類型,或使用現有的表類型,因爲每個表都有同名的行類型。然後你的函數可以返回該行類型。

regress=# CREATE TYPE something123type AS (col1name integer, col2name character varying(300)); 
CREATE TYPE 
regress=# CREATE FUNCTION something123_legacy2(character varying(100)) 
    RETURNS SETOF something123type AS 
    $$ 
     SELECT 1, 'fred'::varchar(300); 
    $$ 
    LANGUAGE SQL; 
CREATE FUNCTION 
regress=# SELECT * FROM something123_legacy2('blah'); 
col1name | col2name 
----------+---------- 
     1 | fred 
(1 row) 

您也可以嘗試使用OUT參數,但我似乎依稀記得,他們在一個點只支持PL/pgSQL的(不是SQL函數),我不知道他們在8.1工作。試試看:

CREATE FUNCTION something123(IN character varying(100), OUT integer, OUT character varying(300)) RETURNS setof record AS 
$$ 
    SELECT b.year, p.materialUsed FROM bestBefore b join packaged p on b.id=p.id WHERE id=$1; 
$$ 
LANGUAGE SQL; 

警告Your PostgreSQL version is unsupported and has been for two years。這是沒有得到安全或錯誤修復。最終你將不得不升級,而你越等待它越難獲得。現在開始計劃升級。閱讀您和當前版本之間每個.0版本(8.2.0,8.3.0等)的版本說明,特別注意升級說明和兼容性說明。注意將隱式轉換刪除到文本,bytea_output更改和standard_conforming字符串更改。閱讀新版本手冊的升級部分,並注意使用新版本pg_dump的建議。

+1

+1更新警告。這個很重要。 – 0xCAFEBABE

+0

好的,謝謝我得到它的工作。我遇到問題的最後一部分是我想比較輸入,所以我去了'$ 1',但我需要刪除''(否則返回0行)。所以如果參數的類型是字符變化的,那麼在引用它時不需要單引號? – Celeritas

+0

@Celeritas ...我不確定你的意思。 ''''與'$ 1'不同'$ 1',如果這就是你要求的;第一個是空字符串,第二個是字符串「$ 1」,另一個擴展爲參數。但是你沒有在你的問題中寫「''',而我沒有在答案中,所以我不確定你在做什麼。你是否問我在上面使用了一個簡單的虛擬語句而不是你的SELECT語句? 'cos只是爲了方便測試。 –