これはさらに簡素化および改善できます:
CREATE OR REPLACE FUNCTION some_f(_tbl regclass, OUT result integer)
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE format('SELECT (EXISTS (SELECT FROM %s WHERE id = 1))::int', _tbl)
INTO result;
END
$func$;
スキーマ修飾名で呼び出す(以下を参照):
SELECT some_f('myschema.mytable'); -- would fail with quote_ident()
または:
SELECT some_f('"my very uncommon table name"');
主なポイント
OUT
を使用する パラメータ 機能を簡素化するため。動的SQLの結果を直接選択して実行できます。追加の変数やコードは必要ありません。
EXISTS
まさにあなたが望むことをします。 true
を取得します 行が存在する場合、またはfalse
そうでなければ。これを行うにはさまざまな方法があります。EXISTS
通常、最も効率的です。
整数が必要なようです 戻ったので、boolean
をキャストしました EXISTS
の結果 integer
、それはあなたが持っていたものを正確に生み出します。 ブール値を返します 代わりに。
オブジェクト識別子タイプregclass
を使用しています _tbl
の入力タイプとして 。これですべてのquote_ident(_tbl)
またはformat('%I', _tbl)
できますが、より良い理由は次のとおりです。
-
..SQLインジェクションを防ぎます 同様に。
-
..テーブル名が無効であるか、存在しないか、現在のユーザーに表示されていない場合は、すぐに失敗し、より適切に失敗します。 (
regclass
パラメータは既存にのみ適用されます テーブル。) -
..スキーマ修飾されたテーブル名で機能します。ここでプレーンな
quote_ident(_tbl)
またはformat(%I)
あいまいさを解決できないため、失敗します。スキーマ名とテーブル名を別々に渡したりエスケープしたりする必要があります。
既存でのみ機能します 明らかに、テーブル。
私はまだformat()
を使用しています 、構文を単純化するため(そして、その使用方法を示すため)、ただし%s
%I
の代わりに 。通常、クエリはより複雑なので、format()
もっと役立ちます。簡単な例では、連結することもできます:
EXECUTE 'SELECT (EXISTS (SELECT FROM ' || _tbl || ' WHERE id = 1))::int'
id
をテーブル修飾する必要はありません FROM
にはテーブルが1つしかないのに列 リスト。この例では、あいまいさはあり得ません。 (動的)EXECUTE
内のSQLコマンド 個別のスコープがある 、関数本体のプレーンSQLコマンドとは対照的に、関数変数またはパラメーターは表示されません。
これがあなたが常にする理由です 動的SQLのユーザー入力を適切にエスケープします:
db<>ここでフィドル SQLインジェクションのデモンストレーション
古いsqlfiddle