2011-07-23 7 views
2

私はPostgreSQLで行をコピーすることについて質問があります。私のテーブル階層は非常に複雑で、多くのテーブルが外部キーを介して互いにリンクされています。わかりやすくするために、2つの表で私の質問を説明しますが、私の実際のケースはもっと複雑です。postgresql - カスケードコピー/挿入

は、私は次の2つの表があるとしましょう:

table A 
(
    integer identifier primary key 
    ... -- other fields 
); 

table B 
(
    integer identifier primary key 
    integer a   foreign key references A (identifier) 
    ... -- other fields 
); 

セイAとBは、以下の行を保持:

A(1) 

B(1, 1) 
B(2, 1) 

私の質問です:私は、行のコピーを作成したいですB内の関連する行も新しい行にコピーされます。これは与えるだろう:基本的に私はCOPY/INSERT CASCADEを探しています

A(1) -- the old row 
A(2) -- the new row 

B(1, 1) -- the old row 
B(2, 1) -- the old row 
B(3, 2) -- the new row 
B(4, 2) -- the new row 

多かれ少なかれ自動的にこれを達成するための素敵なトリックはありますか?たぶん一時テーブルを使用して?

INSERT INTO ... FROM ...私は正しい順序で物事を質問し、私は精神的になるかもしれないと私は信じています。

更新

はのは、自分の質問に答えてみましょう;)

私はPostgreSQLのRULEメカニズムといくつか試しアウトを行なったし、これは私が思い付いたものです:

まず、テーブル定義:

drop table if exists A cascade; 
drop table if exists B cascade; 

create table A 
(
     identifier    serial     not null    primary key, 
     name     varchar     not null 
); 

create table B 
(
     identifier    serial     not null    primary key, 
     name     varchar     not null, 
     a      integer     not null    references A (identifier) 
); 

次に、テーブルごとに、tran UPDATEをINSERTにスレートします。

create function A(in A, in A) returns integer as 
$$ 
     declare 
       r integer; 
     begin 
       -- A 
       if ($1.identifier <> $2.identifier) then 
         insert into A (identifier, name) values ($2.identifier, $2.name) returning identifier into r; 
       else 
         insert into A (name) values ($2.name) returning identifier into r; 
       end if; 

       -- B 
       update B set a = r where a = $1.identifier; 

       return r; 
     end; 
$$ language plpgsql; 

create rule A as on update to A do instead select A(old, new); 

create function B(in B, in B) returns integer as 
$$ 
     declare 
       r integer; 
     begin 
       if ($1.identifier <> $2.identifier) then 
         insert into B (identifier, name, a) values ($2.identifier, $2.name, $2.a) returning identifier into r; 
       else 
         insert into B (name, a) values ($2.name, $2.a) returning identifier into r; 
       end if; 

       return r; 
     end; 
$$ language plpgsql; 

create rule B as on update to B do instead select B(old, new); 

は最後に、いくつかのtestings:

insert into A (name) values ('test_1'); 
insert into B (name, a) values ('test_1_child', (select identifier from a where name = 'test_1')); 

update A set name = 'test_2', identifier = identifier + 50; 
update A set name = 'test_3'; 

select * from A, B where B.a = A.identifier; 

これは非常に正常に動作するようです。コメントはありますか?

+0

純粋なデカルト製品をお探しですか?もしそうなら、あなたは面倒を見る必要はありませんでしたが、ON句を使用せずにAとBを結合できました。 – Kenaniah

答えて

0

これは動作します。あなたが賢明に避けたことは、挿入と更新に関するDO ALSOのルールでした。挿入と更新を行うとかなり危険ですので、ほとんどすべてのコストでそれを避けてください。

しかしながら、トリガーはさらに悪化し、ハードコーナーが少なくなることはありません。

関連する問題