結果セットを返す動的に構築されたSQLステートメントを含むストアドプロシージャを作成するにはどうすればよいですか?これが私のサンプルコードです:
CREATE OR REPLACE FUNCTION reporting.report_get_countries_new (
starts_with varchar,
ends_with varchar
)
RETURNS TABLE (
country_id integer,
country_name varchar
) AS
$body$
DECLARE
starts_with ALIAS FOR $1;
ends_with ALIAS FOR $2;
sql VARCHAR;
BEGIN
sql = 'SELECT * FROM lookups.countries WHERE lookups.countries.country_name >= ' || starts_with ;
IF ends_with IS NOT NULL THEN
sql = sql || ' AND lookups.countries.country_name <= ' || ends_with ;
END IF;
RETURN QUERY EXECUTE sql;
END;
$body$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
COST 100 ROWS 1000;
このコードはエラーを返します:
ERROR: syntax error at or near "RETURN"
LINE 1: RETURN QUERY SELECT * FROM omnipay_lookups.countries WHERE o...
^
QUERY: RETURN QUERY SELECT * FROM omnipay_lookups.countries WHERE omnipay_lookups.countries.country_name >= r
CONTEXT: PL/pgSQL function "report_get_countries_new" line 14 at EXECUTE statement
私はこれの代わりに他の方法を試しました:
RETURN QUERY EXECUTE sql;
方法1:
RETURN EXECUTE sql;
方法2:
sql = 'RETURN QUERY SELECT * FROM....
/*later*/
EXECUTE sql;
すべての場合で成功しませんでした。
最終的には、動的SQLステートメントを含み、動的SQLステートメントから結果セットを返すストアドプロシージャを作成したいと思います。
改善の余地があります:
_CREATE OR REPLACE FUNCTION report_get_countries_new (starts_with text
, ends_with text = NULL)
RETURNS SETOF lookups.countries AS
$func$
DECLARE
sql text := 'SELECT * FROM lookups.countries WHERE country_name >= $1';
BEGIN
IF ends_with IS NOT NULL THEN
sql := sql || ' AND country_name <= $2';
END IF;
RETURN QUERY EXECUTE sql
USING starts_with, ends_with;
END
$func$ LANGUAGE plpgsql;
-- the rest is default settings
_
PostgreSQL 8.4では、USING
にEXECUTE
句が導入されました。これは、いくつかの理由で役立ちます。 マニュアルの要約 :
コマンド文字列は、コマンドで_
$1, $2
_などとして参照されるパラメータ値を使用できます。これらの記号は、USING
句で指定された値を参照します。この方法は、データ値をテキストとしてコマンド文字列に挿入するよりも望ましい場合がよくあります。値をテキストに変換したり元に戻したりする実行時のオーバーヘッドを回避し、引用符や引用符を使用する必要がないため、SQLインジェクション攻撃を受けにくくなります。脱出。
IOW、quote_literal()
でサニタイズした場合でも、パラメーターのテキスト表現を使用してクエリ文字列を作成するよりも安全で高速です。
クエリ文字列の_$1, $2
_は、USING
句で指定された値を参照し、notは関数パラメータを参照することに注意してください。
_SELECT * FROM lookups.countries
_を返す間、次のようにRETURN
宣言を簡略化できます。
_RETURNS SETOF lookups.countries
_
PostgreSQLには、すべてのテーブルに対して自動的に定義された複合タイプがあります。これを使って。その結果、関数はタイプによって異なり、テーブルを変更しようとするとエラーメッセージが表示されます。このような場合は、関数を削除して再作成してください。
これは望ましい場合と望ましくない場合があります-一般的にはそうです!テーブルを変更する場合は、副作用を認識しておく必要があります。あなたがそれを持っている方法では、あなたの関数は静かに壊れて、次の呼び出しで例外を発生させます。
示されているように、宣言の2番目のパラメーターに explicit default を指定すると、次のことができます(ただし、そうする必要はありません)。 )_ends_with
_で上限を設定したくない場合は、呼び出しを単純化します。
_SELECT * FROM report_get_countries_new('Zaire');
_
の代わりに:
_SELECT * FROM report_get_countries_new('Zaire', NULL);
_
このコンテキストでは 関数のオーバーロード に注意してください。
(今のところ)許容できる場合でも、言語名_
_を引用しないでください。それは識別子です。'plpgsql'
宣言時に変数を割り当てることができます。余分なステップを節約します。
パラメータはヘッダーで指定されます。無意味な行を削除します。
_ starts_with ALIAS FOR $1;
ends_with ALIAS FOR $2;
_