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

PL/pgSQLのEXECUTE...INTO ... USING文はレコードに実行できませんか?

    投稿された回答のより簡単な代替手段。パフォーマンスが大幅に向上するはずです。

    この関数は、指定されたテーブル( in_table_name )から行を取得します )および主キー値( in_row_pk )、それを新しい行として同じテーブルに挿入し、一部の値を置き換えます( in_override_values )。デフォルトの新しい主キー値が返されます( pk_new

    CREATE OR REPLACE FUNCTION f_clone_row(in_table_name regclass
                                         , in_row_pk int
                                         , in_override_values hstore
                                         , OUT pk_new int) AS
    $func$
    DECLARE
       _pk   text;  -- name of PK column
       _cols text;  -- list of names of other columns
    BEGIN
    
    -- Get name of PK column
    SELECT INTO _pk  a.attname
    FROM   pg_catalog.pg_index     i
    JOIN   pg_catalog.pg_attribute a ON a.attrelid = i.indrelid
                                    AND a.attnum   = i.indkey[0]  -- 1 PK col!
    WHERE  i.indrelid = 't'::regclass
    AND    i.indisprimary;
    
    -- Get list of columns excluding PK column
    _cols := array_to_string(ARRAY(
          SELECT quote_ident(attname)
          FROM   pg_catalog.pg_attribute
          WHERE  attrelid = in_table_name -- regclass used as OID
          AND    attnum > 0               -- exclude system columns
          AND    attisdropped = FALSE     -- exclude dropped columns
          AND    attname <> _pk           -- exclude PK column
          ), ',');
    
    -- INSERT cloned row with override values, returning new PK
    EXECUTE format('
       INSERT INTO %1$I (%2$s)
       SELECT %2$s
       FROM  (SELECT (t #= $1).* FROM %1$I t WHERE %3$I = $2) x
       RETURNING %3$I'
     , in_table_name, _cols, _pk)
    USING   in_override_values, in_row_pk -- use override values directly
    INTO    pk_new;                       -- return new pk directly
    
    END
    $func$ LANGUAGE plpgsql;
    

    電話:

    SELECT f_clone_row('t', 1, '"col1"=>"foo_new","col2"=>"bar_new"'::hstore);
    

    SQLFiddle。

    • regclassを使用します 入力パラメータタイプとして、有効なテーブル名のみを最初に使用でき、SQLインジェクションは除外されます。不正なテーブル名を指定する必要がある場合も、関数はより早く、より適切に失敗します。

    • OUTを使用する パラメータ( pk_new )構文を単純化するため。

    • 主キーの次の値を手動で把握する必要はありません。自動的に挿入され、事後に返されます。これは、単純で高速であるだけでなく、シーケンス番号の無駄や順序の乱れも回避できます。

    • format() 動的クエリ文字列のアセンブリを簡素化し、エラーが発生しにくくするため。識別子と文字列にそれぞれ位置パラメータを使用する方法に注意してください。

    • 私はあなたの暗黙の仮定に基づいています 許可されたテーブルには、整数型の単一の主キー列とデフォルトの列があります 。通常、シリアル 列。

    • 関数の重要な要素は、最後の INSERTです。 :

      • #= オペレーター 副選択で、結果の行をすぐに分解します。
      • 次に、メインの SELECTで関連する列のみを選択できます 。
      • PostgresにPKのデフォルト値を割り当てさせ、 RETURNINGで元に戻します。 条項。
      • 戻り値をOUTに書き込みます パラメータを直接。
      • すべてが単一のSQLコマンドで実行され、通常は最速です。


    1. Oracleを使用してDjangoで自動テストを作成する際のORA-65096エラーの修正

    2. OracleLOBを削除する方法

    3. Oracle(+)演算子

    4. SQLでタプルのグループを比較する方法