web-dev-qa-db-ja.com

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の関数作成に慣れていないので、どんな助けでもありがたいです。 return intが間違っているように感じますが、返された行のすべての列を返すようにするために他に何を置くべきかわかりません。ありがとう!

13
j.gardner117

そのような識別子の代わりに変数を使用することはできません。動的クエリでそれを行う必要があります。次のようになります。

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

PostgreSQL 9.1以降を使用している場合は、 format()関数 を使用できます。これにより、この文字列の作成がはるかに簡単になります。

18
Matthew Wood

テーブル名と列名は、動的ステートメントとして実行する文字列を動的に作成しない限り、パラメーターまたは変数として指定することはできません。 Postgresには、 動的ステートメントの実行 に関する優れた入門ドキュメントがあります。識別子とリテラルを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;
14
dbenhur