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

トリガー関数で動的テーブル名を使用してINSERT

    PostgreSQL9.1以降

    format() 識別子をエスケープする方法が組み込まれています。以前よりもシンプル:

    CREATE OR REPLACE FUNCTION foo_before()
      RETURNS trigger AS
    $func$
    BEGIN
       EXECUTE format('INSERT INTO %I.%I SELECT $1.*'
                    , TG_TABLE_SCHEMA, TG_TABLE_NAME || 'shadow')
       USING OLD;
    
       RETURN OLD;
    END
    $func$  LANGUAGE plpgsql;
    

    VALUESで動作します 式も。

    db<>ここでフィドル
    古いsqlfiddle。

    主なポイント

    • format()を使用する またはquote_ident() 識別子を(自動的に、必要な場合にのみ)引用することで、SQLインジェクションや単純な構文違反から保護します。
      これは必要です 、自分のテーブル名でも!
    • スキーマ-テーブル名を修飾します。現在のsearch_pathによって異なります ベアテーブル名を設定すると、別のスキーマにある同じ名前の別のテーブルに解決される可能性があります。
    • EXECUTEを使用します 動的DDLステートメントの場合。
    • 値を渡す USINGで安全に 条項。
    • plpgsqlでの動的コマンドの実行に関する詳細なマニュアルを参照してください。
    • RETURN OLD;に注意してください トリガーにはトリガー機能が必要ですBEFORE DELETE 。詳細はこちらのマニュアルをご覧ください。

    エラーメッセージが表示されます OLDのため、ほぼ成功したバージョンで 表示されない EXECUTE内 。また、試したように分解された行の個々の値を連結する場合は、quote_literal()を使用してすべての列のテキスト表現を準備する必要があります。 有効な構文を保証します。また、知っている必要があります 事前に列名を処理して、システムカタログを照会します。これは、単純で動的なトリガー関数を使用するという考えに反します...

    私のソリューションは、これらすべての合併症を回避します。また、少し簡略化されています。

    PostgreSQL9.0以前

    format() まだ利用できないので:

    CREATE OR REPLACE FUNCTION foo_before()
      RETURNS trigger AS
    $func$
    BEGIN
        EXECUTE 'INSERT INTO ' || quote_ident(TG_TABLE_SCHEMA)
                        || '.' || quote_ident(TG_TABLE_NAME || 'shadow')
                        || ' SELECT $1.*'
        USING OLD;
    
        RETURN OLD;
    END
    $func$  LANGUAGE plpgsql;
    

    関連:

    • PostgreSQL 8.2でTG_TABLE_NAMEを動的に使用するにはどうすればよいですか?


    1. 例を使用したOracleの一意キー

    2. 単語と数字の混合文字列の人間化または自然数の並べ替え

    3. SQL Server 2016:ビューデザイナー

    4. NULL ONNULLINPUTを使用してUDFのパフォーマンスを向上させる