Postgres动态查询功能

j.g*_*117 13 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;
Run Code Online (Sandbox Code Playgroud)

这给了我运行时错误"关系'tname'不存在".我是Postgres的新功能,所以任何帮助都表示赞赏.我觉得返回int是错误的,但我不知道还有什么可以让它返回返回行的所有列.谢谢!

Mat*_*ood 18

您不能使用变量代替这样的标识符.您需要使用动态查询.它看起来像这样:

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

如果您使用的是PostgreSQL 9.1或更高版本,则可以使用format()函数,这使得构造此字符串变得更加容易.


dbe*_*hur 14

如果不动态构造要作为动态语句执行的字符串,则不能将表和列名指定为参数或变量.Postgres有关于执行动态语句的优秀介绍性文档.用quote_ident()或正确引用标识符和文字是很重要的quote_literal().该格式()功能可以帮助清理动态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;
Run Code Online (Sandbox Code Playgroud)