У меня есть вопрос о копировании строк в 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 ... в правильном порядке и тому подобном, я могу сойти с ума.
обновление
Давайте ответим на мой собственный вопрос;)
Я провел некоторые попытки с механизмами RULE в 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)
);
Далее для каждой таблицы мы создаем функцию и соответствующее правило, которое переводит 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);
Наконец, некоторые тесты:
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;
Кажется, это работает вполне нормально.Есть комментарии?