私は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;
これは非常に正常に動作するようです。コメントはありますか?
純粋なデカルト製品をお探しですか?もしそうなら、あなたは面倒を見る必要はありませんでしたが、ON句を使用せずにAとBを結合できました。 – Kenaniah