Postgres动态查询功能

时间:2012-05-17 16:48:10

标签: sql postgresql plpgsql

我需要创建一个函数,该函数将运行查询并返回结果,其中包含表名和列名,这些名称是赋予函数的arugments。我目前有这个:

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是错误的,但我不知道还有什么可以让它返回返回行的所有列。谢谢!

2 个答案:

答案 0 :(得分:18)

您无法使用变量代替此类标识符。您需要使用动态查询。它看起来像这样:

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

如果您使用的是PostgreSQL 9.1或更高版本,则可以使用the format() function,这样可以更轻松地构建此字符串。

答案 1 :(得分:14)

如果不动态构造要作为动态语句执行的字符串,则不能将表和列名指定为参数或变量。 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;