11

1 つのテーブルへの挿入を他の 2 つのテーブルへの挿入に分割する書き換えルールを使用すると、挿入された値の 1 つがデフォルトとして nextval('some_sequence') として両方のテーブルで同じシーケンスを持つ場合、挿入されたデフォルト値は二つのテーブル。これはおそらく、書き換え規則による単純なテキスト置換によるものです。代わりに、デフォルト値が最初に解決され、次に同じ値が両方のテーブルに書き込まれることを望んでいました。

ここに例があります(おそらくご想像のとおり、私はルールを使用して特殊化/一般化を実装しようとしています):

-- first and third commands can be skipped if id is defined as serial
create sequence parents_id_seq;
create table Parents(
  id integer default(nextval('parents_id_seq')) primary key,
  type varchar(50) not null check(type in ('Child1', 'Child2')),
  unique (id, type),
  attribute1 varchar(50) not null unique check(length(attribute1) > 0)
);
alter sequence parents_id_seq owned by parents.id;

第 1 種の子に固有のデータは、

create table Partial_Children1(
  id integer default(nextval('parents_id_seq')) primary key,
  type varchar(50) not null check(type = 'Child1'),
  foreign key (id, type) references Parents(id, type),
  attribute2 varchar(50) not null check(length(attribute2) > 0)
);

次に、上記の両方のテーブルを結合するビュー Children1 を定義しました (ドキュメントに従ってビューを定義するために PostgreSQL が行うことを明示的に記述して、ビューを書き直しました)。

create table Children1(
  id int default(nextval('parents_id_seq')),
  type varchar(50) not null check(type in ('Child1')),
  attribute1 varchar(50) not null check(length(attribute1) > 0),
  attribute2 varchar(50) not null check(length(attribute2) > 0)
);
create rule "_RETURN" as on select to Children1 do instead
  select p.*, c.attribute2
  from Parents p
    join Partial_Children1 c
      on p.id = c.id;

最後に、私が問題を抱えている書き換えルール:

create rule ct_i_children1 as
  on insert to Children1
  do instead (
    insert into Parents(attribute1, type)
      values(new.attribute1, 'Child1');
    insert into Partial_Children1(attribute2, type)
      values(new.attribute2, 'Child1');
  );

でデータを挿入しようとしています

insert into Children1 (attribute1, attribute2)
  values ('a1', 'a2'),
         ('b1', 'b2');

エラーメッセージが表示されます

ERROR:  insert or update on table "partial_children1" violates foreign key constraint "partial_children1_id_fkey"
DETAIL:  Key (id,type)=(3,Child1) is not present in table "parents".

これを解決する方法は、書き換えルールの 2 番目の挿入を次のように置き換えることです。

insert into Partial_Children1(id, attribute2, type)
  select p.id, new.attribute2, p.type
    from Parents p
    where p.attribute1 = new.attribute1

しかし、これは属性 1 の一意性に依存しているため、強制したくありません。もう 1 つの解決策は、最初に値を一時テーブルに挿入し、次に 2 つのテーブルへの挿入のためにそこから 2 回選択することです。しかし、パフォーマンス上の理由から、私はそれが好きではありません。

両方のテーブルで同じデフォルト値を取得する方法を別のアイデアを持っている人はいますか (トリガーではなくルールを使用するだけです)。

4

2 に答える 2

6

ドキュメントから http://www.postgresql.org/docs/8.4/static/rules.html

これ (ルール システム) は、ルールを考慮してクエリを変更し、変更されたクエリをクエリ プランナーに渡して計画と実行を行います。

そのため、最初に何も実行せずにクエリを書き換えます。

複数のレコードを一度に挿入しない場合に機能させることができます。

create or replace rule ct_i_children1 as
  on insert to Children1
  do instead (
    insert into Parents(id, attribute1, type)
      values(nextval('parents_id_seq'), new.attribute1, 'Child1');
    insert into Partial_Children1(id, attribute2, type)
      values(currval('parents_id_seq'), new.attribute2, 'Child1');
  );

次に、次のことができます。

insert into Children1 (attribute1, attribute2) values ('a1', 'a2');
insert into Children1 (attribute1, attribute2) values ('b1', 'b2');

だがしかし

insert into Children1 (attribute1, attribute2)
  values ('a1', 'a2'),
         ('b1', 'b2');

したがって、トリッキーな currval() 呼び出しでルール システムを使用するべきではありません。

さらに、これらのページのコメントを見てください。

もう 1 つのヒント: postgresql メーリング リストでのサポートは、データベース エンジン自体と同じくらい優れています。

ところで、postgresql がそのまま継承をサポートしていることをご存知ですか?

まとめ: トリガーを使用するか、複数行の挿入を避ける必要があります。

于 2010-02-23T16:16:02.807 に答える
0

ルールがそれを行います - 実行前にクエリを書き換えます。

ベース (Children1) の実際のテーブルがある限り、RULE の代わりに TRIGGER を使用して同じことを達成できると思います。

于 2009-08-25T12:25:23.117 に答える