[pgsql-jp: 27939] view/rule/insert

Satoshi Nagayasu snaga @ snaga.org
2002年 11月 12日 (火) 07:23:21 JST


永安です。

一言で言うと、「あれば select、無ければ insert して select」というのを
どのように書くのか、ということだと思うのですが…。

create table t1 (
  c1_id integer references c1 ( c1_id ),
  memo text
);

create table c1 (
  c1_name text primary key,
  c1_id serial
);

のように、外部参照のあるテーブルをviewでくるんで、
ユーザーにはひとつのテーブルのように見せるとします。

create view c1v as
  select c1.c1_name,t1.memo
    from c1,t1
   where c1.c1_id = t1.c1_id;

つまり、c1_id という serial をユーザーには見えないように
するわけですが。

この時、データの追加や更新のために、ユーザーがc1vにアクセスしますが、
viewを通しては更新できないので、ruleを用いてc1vへのinsertを
書き換えるとします。

とりあえず、以下のように作りました。

create rule c1v_ins as
  on insert to c1v
  do instead
    insert into t1 values (
      (select c1_id from c1 where c1.c1_name=new.c1_name),
      new.memo
    );

この際、t1.c1_id が参照している c1.c1_id が先に存在していないと
いけないわけですが、c1v に insert する時点では、c1.c1_id に該当する
レコードがあるかもしれないし、無いかもしれない、という状況です。

c1 に該当レコードがあった場合には、単に select して c1_id を取得し、
無い場合には、insert してから select して c1_id を取得したい。
で、その c1_id を使って t1 に insert したい、というのを
rule で書くにはどうすればいいのでしょう?

      (select c1_id from c1 where c1.c1_name=new.c1_name),

の部分を、c1の参照先に該当レコードがあってもなくても、
成功するようにしたいのです(というか無ければinsertしたい)。
primary key制約を入れてるので、2レコード以上が返ることはありません。

rule の do 〜 の中で制御構造は書けるのか?ということじゃないかと
思うのですが、あれば select、無ければ insert して select、と
いうのはどのように書けばいいのでしょうか?

とりあえず、あろうが無かろうが insert してみる、というのも
アリと言えばアリなのでしょうが、それだとキーがカチ合って
insertが失敗したときに、トランザクションがまるごとabortしそうな
気がします…(というか試してみたらabortしました。当然ですね…)。


実際に作ってるものは、4つくらいの外部参照があって、
それをviewにくるんでいるので、すべての外部参照先に対する
「あればselect、なければinsertしてselect」というのを、
viewに対する一つのinsert(のdo〜句)ににおいて
implicitに呼び出したいのですが。

そーゆーときはこーやるもんだ、みたいなセオリーがありましたら、
どなたかお教えくださると助かります。

あと、質問の意味が分からなかったらご指摘いただけると幸いです。

よろしくお願いします。

-- 
NAGAYASU Satoshi <snaga @ snaga.org>




pgsql-jp メーリングリストの案内