15

Postgres の「パーティショニング」機能を使用するテーブルがいくつかあります。各テーブルに共通の BEFORE INSERT OF ROW トリガーを定義して、1) 親テーブルに対して挿入が発生した場合にパーティションを動的に作成し、2) パーティションに対して挿入を再実行します。

何かのようなもの:

CREATE OR REPLACE FUNCTION partition_insert_redirect( )
RETURNS trigger AS $BODY$
BEGIN
  ... create the new partition and set up the redirect Rules ...

  /* Redo the INSERT dynamically.  The new RULE will redirect it to the child table */
  EXECUTE 'INSERT INTO ' || quote_ident(TG_TABLE_SCHEMA) || '.' || quote_ident(TG_TABLE_NAME) ||
          ' SELECT NEW.*'
END

しかし、「NEW」レコードは、EXECUTE SQL 内には表示されません。この作業をできるだけ簡単にするにはどうすればよいですか?

別の方法として、NEW レコードのフィールドを反復処理できますか?

私は一時テーブルを使用することを考えました:

EXECUTE 'CREATE TEMPORARY TABLE new_row (LIKE ' ||
        quote_ident(TG_TABLE_SCHEMA) || '.' || quote_ident(TG_TABLE_NAME) ||
        ') ON COMMIT DROP';

INSERT INTO new_row SELECT NEW.*;

EXECUTE 'INSERT INTO ' || quote_ident(TG_TABLE_SCHEMA) || '.' || quote_ident(TG_TABLE_NAME) ||
       ' SELECT * FROM new_row';
DROP TABLE new_row;

しかし、一時テーブルへの参照がキャッシュされているため、これも機能しません: PL/PgSQL 関数で一時テーブルにアクセスすると、「OID ##### との関係が存在しません」というエラーが発生するのはなぜですか?

Postgres 8.2 を使用していますが、他のバージョンに変更できません。

EDIT:
@alvherreが指摘したように、これはおそらくEXECUTE ... USING構文を使用してPostgres 8.4で実行できます。http://wiki.postgresql.org/wiki/PL/pgSQL_Dynamic_Triggersの例を参照してください。

4

3 に答える 3

22

EXECUTE USINGNEW を渡すために使用できます。あなたの例は

EXECUTE 'INSERT INTO ' || TG_RELID || '::regclass SELECT $1' USING NEW;

(TG_TABLE_SCHEMA と TABLE_NAME をいじる代わりに、regclass にキャストされた TG_RELID を使用することに注意してください。これは、非標準の場合に使いやすいためです。ただし、とにかく、plpgsql は非標準です。)

于 2010-01-04T03:49:52.497 に答える
3

はい、EXECUTE ... USING は 8.4 で使用できます。例えば:

EXECUTE 'INSERT INTO ' || table_name || ' SELECT $1.*' USING NEW;

下位バージョン (私は 8.3 でしかテストしていません) では、以下を使用できます。

EXECUTE 'INSERT INTO ' || table_name ||
    ' SELECT (' || quote_literal(NEW) || '::' || TG_RELID::regclass || ').*';
于 2010-08-09T04:30:23.087 に答える