sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQL関数パラメーターとしてのテーブル名

    これはさらに簡素化および改善できます:

    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



    1. 10進数(s、p)または数値(s、p)?

    2. SQLServerでGOTOを使用する方法

    3. バックグラウンドスレッドでSQLiteクエリを非同期で実行するにはどうすればよいですか?

    4. MySQLのストアドプロシージャ内にオプションのパラメータを記述しますか?