我有一個關於在PostgreSQL中複製行的問題。我的表層次結構非常複雜,許多表通過外鍵相互關聯。爲了簡單起見,我將用兩張表格來解釋我的問題,但請記住,我的實際情況需要更多的複雜性。postgresql - 級聯複製/插入
說我有以下兩個表:
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)
我的問題是:我想在創建行的副本A使B中的相關行也被複制到新行中。這將使:
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
基本上我尋找一個COPY/INSERT CASCADE。
有沒有一個簡單的技巧來實現這個或多或少的自動?也許通過使用臨時表?
我相信,如果我必須寫出所有的INSERT INTO ... FROM ...以正確的順序和內容查詢自己,我可能會精神失常。
更新
讓我們來回答我的問題;)
我做了一些試奏與PostgreSQL的規則機制,這是我想出了:
首先,表定義:
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