4

hstoreをループし、レコードの列 ( のキーhstore) を特定の値 ( の値) に設定する関数の領域を PL/pgSQL に書き込もうとしていますhstore。Postgres 9.1 を使用しています。

は次のhstoreようになります。' "column1"=>"value1","column2"=>"value2" '

一般に、 を取り、hstore変更する値を持つレコードを持つ関数から私が望むものは次のとおりです。

FOR my_key, my_value IN
    SELECT key,
           value
      FROM EACH( in_hstore )
LOOP
    EXECUTE 'SELECT $1'
       INTO my_row.my_key
      USING my_value;
END LOOP;

このコードで発生しているエラー:

"myrow" has no field "my_key". 私はかなり長い間解決策を探してきましたが、同じ結果を達成するために試みた他のすべてのことはうまくいきませんでした.

4

2 に答える 2

10

投稿された回答のより簡単な代替。はるかに優れたパフォーマンスを発揮するはずです。

この関数は、指定されたテーブル ( 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);

SQL フィドル。

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

  • OUTパラメーター ( ) を使用してpk_new、構文を簡素化します。

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

  • format()動的クエリ文字列の組み立てを簡素化し、エラーを起こしにくくするために使用します。識別子と文字列にそれぞれ位置パラメータを使用する方法に注意してください。

  • 許可されたテーブルには、列のデフォルトを持つ整数型の単一の主キー列があるという暗黙の仮定に基づいています。通常は列。serial

  • 関数の重要な要素は finalINSERTです:

    • #=副選択で演算子を使用してオーバーライド値を既存の行とマージし、結果の行をすぐに分解します。
    • 次に、メインで関連する列のみを選択できますSELECT
    • Postgres に PK のデフォルト値を割り当てさせ、RETURNING句でそれを取得します。
    • 戻り値をOUTパラメーターに直接書き込みます。
    • すべてが単一の SQL コマンドで実行されるため、一般的に最速です。
于 2013-07-15T22:34:13.550 に答える