2012-05-17 58 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

我该如何给它列定义列表?有什么办法来动态拉这个? –