2012-05-17 57 views
11

我需要創建一個函數,該函數將運行查詢並返回結果,其中表名和列名是賦予該函數的參數。我目前有這樣的:Postgres動態查詢函數

CREATE OR REPLACE FUNCTION qa_scf(tname character varying, cname character varying) 
RETURNS SETOF INT AS 
$BODY$ 
BEGIN 
RETURN QUERY SELECT * FROM tname WHERE cname !='AK' AND cname!='CK'; 
END; 
$BODY$ 
LANGUAGE plpgsql VOLATILE 
COST 100 
ROWS 1000; 

這給了我錯誤「關係」tname'不存在「運行時。我是新的功能創建Postgres,所以任何幫助表示讚賞。我覺得返回int是錯的,但我不知道還有什麼可以讓它返回返回行的所有列。謝謝!

回答

17

您不能使用變量來代替這樣的標識符。你需要用動態查詢來完成。如果您在使用PostgreSQL 9.1

EXECUTE 'SELECT * FROM ' || quote_ident(tname) 
     || ' WHERE ' || quote_ident(cname) || ' NOT IN (''AK'',''CK'');' 
INTO result_var; 

或以上,你可以使用the format() function這使得構建此字符串容易得多:它會是這個樣子。

+0

我該如何聲明result_var爲? –

+1

切勿在不使用適當的quote_FOO()函數的情況下將值插入動態sql語句中,否則您會打開注入攻擊的大門。 – dbenhur

+0

這是一個面向內部的數據庫。 –

13

表名和列名不能指定爲參數或變量,不能動態構造要作爲動態語句執行的字符串。 Postgres有關於executing dynamic statements的優秀入門文檔。正確引用quote_ident()quote_literal()的標識符和文字很重要。 format()函數有助於清理動態SQL語句的構造。既然你聲明函數返回SETOF INTEGER,你應該選擇你想要的整數字段,而不是*

CREATE OR REPLACE FUNCTION qa_scf(tname text, cname text) 
RETURNS SETOF INTEGER AS 
$BODY$ 
BEGIN 
    RETURN QUERY EXECUTE format(
    'SELECT the_integer_field FROM %I WHERE %I NOT IN (%L, %L)', 
            tname, cname, 'AK', 'CK' 
); 
END; 
$BODY$ 
LANGUAGE plpgsql; 
+0

如何讓它返回所有列? –

+0

您可以'SELECT *'並聲明'RETURNS SETOF RECORD'。然後消費者必須瞭解記錄元組。 http://wiki.postgresql.org/wiki/Return_more_than_one_row_of_data_from_PL/pgSQL_functions – dbenhur

+0

我該如何給它列定義列表?有什麼辦法來動態拉這個? –