2015-08-25 2 views
0

Я прошу ваше мнение узнать, возможно ли это, потому что я ноб, и, возможно, я пытаюсь сделать это совершенно неправильно. Я много искал, но ничего не нашел, возможно, не используя правильные критерии поиска.
Я использую Postgresql 9.1. Я упростил ситуацию, чтобы понять методПовторяющиеся данные по таблицам, содержащим референции Идентификаторы

У меня есть 3 таблицы:

  • таблицу А (мастер)
  • таблица В (связанном с таблицей А)
  • таблицей С (связанным с таблицей Б)

(см схему)

Таблица A

id_A | data_A 
    -----+-------- 
    A01 | dataA01 
    A02 | dataA02 

Таблица B

id_B | ref_id_A | data_B 
    -----+----------+-------- 
    B01 | A01 | dataB01 
    B02 | A01 | dataB02 
    B03 | A02 | dataB03 
    B04 | A02 | dataB04 
    B05 | A02 | dataB05 
    B06 | A02 | dataB06 

Таблица C

id_C | ref_id_B | data_C 
    -----+----------+-------- 
    C01 | B01 | dataC01 
    C02 | B01 | dataC02 
    C03 | B02 | dataC03 
    C04 | B02 | dataC04 

То, что я пытаюсь сделать, это скопировать все данные, связанные с таблицей А, сохраняя все данные и referencies, которые хранятся в таблицах B и C с новыми идентификаторами. Он должен работать, как копирование и вставка, чтобы поддерживать старые версии во время работы над новым

дубликата A01 -> A03

Таблица A

id_A | data_A 
    -----+-------- 
    A01 | dataA01 
    A02 | dataA02 
    A03 | dataA01 

Таблица B

id_B | ref_id_A | data_B 
    -----+----------+-------- 
    B01 | A01 | dataB01 
    B02 | A01 | dataB02 
    B03 | A02 | dataB03 
    B04 | A02 | dataB04 
    B05 | A02 | dataB05 
    B06 | A02 | dataB06 
    B07 | A03 | dataB01 
    B08 | A03 | dataB02 

Таблица C

id_C | ref_id_B | data_C 
    -----+----------+-------- 
    C01 | B01 | dataC01 
    C02 | B01 | dataC02 
    C03 | B02 | dataC03 
    C04 | B02 | dataC04 
    C05 | B07 | dataC01 
    C06 | B07 | dataC02 
    C07 | B08 | dataC03 
    C08 | B08 | dataC04 

Я написал этот запрос, чтобы дублировать А01 и он держит отлично данные в таблице B, но я не в состоянии дублировать данные в таблице C

WITH new_id_A as 
(insert into table_A (id_A, data_A) (select id_A, data_A from table_A where id_A='A01') returning id_A) 
insert into table_B (ref_id_A, data_B) select (select id_A from new_id_A) as ref_id_A, data_B from table_B where ref_id_A='A01'; 

Я пробовал разные подходы, но без каких-либо результатов
я могу выполнить задача легко с помощью кода, но я бы предпочел, чтобы закончить его в то базе данных в одной транзакции
Спасибо за ваше внимание

+0

Как вы генерировать идентификаторы в таблицах?В идеале это будет последовательность. В этом случае вставка «Копия» данных не должна быть сложной задачей. – Bulat

+0

Вы можете написать триггер, чтобы обновить «Таблицу B» новым идентификатором, когда изменяется таблица «A». – Colin

+0

@Bulat ID - это серийный автоинкрементный, без возможности изменить структуру таблицы для хранения буквенно-цифровых идентификаторов без изменения всех таблиц. Но это хорошая идея, если я сделаю новый db –

ответ

0

Я думаю, вы должны поставить идентификаторы для новых строк в временной таблице, как это для простоты:

WITH new_id_A as 
(insert into table_A (id_A, data_A) (select id_A, data_A from table_A where id_A='A01') returning id_A) 
SELECT 'A01' AS old_id, id_A AS new_id 
INSERT INTO TEMP table_A_copy; 

insert into table_B (ref_id_A, data_B) 
select cp.new_id, b.data_B 
from 
table_A_copy cp INNER JOIN 
table_B b ON b.ref_id_A = cp.old_id; 

insert into table_C (ref_id_B, data_B) 
select b_new.id_B, c.data_C 
from 
table_A_copy cp INNER JOIN 
table_b b_old on b_old.ref_id_a = cp.old_id inner join 
table_b b_new on b_new.ref_id_a = cp.new_id inner join 
table_C c ON c.ref_id_B = b_old.id_B; 

Обновление от Fabio:

drop table if exists table_a_copy; 
create temp table table_a_copy ("old_id" integer, "new_id" integer); 

with new_id_a as 
(insert into table_a (data_a) 
    (select data_a from table_a where id_a='1') returning id_a) 
insert into table_a_copy select '1'::integer as old_id, 
    (select * from new_id_a) as new_id; 

-- Insert to table B 
insert into table_b (ref_id_a, data_b) 
select cp.new_id, b.data_b 
from 
    table_a_copy cp inner join 
    table_b b on b.ref_id_a = cp.old_id; 

-- Insert to table C 
insert into table_c (ref_id_B, data_C) 
select b_new.id_b, c.data_c 
from 
    table_a_copy cp inner join 
    table_b b_old on b_old.ref_id_a = cp.old_id inner join 
    table_b b_new on b_new.ref_id_a = cp.new_id inner join 
    table_c c on c.ref_id_b = b_old.id_b; 
+0

Пробовал ваш код, но не работал, проблемы с выбором временной таблицы temp. Таким образом, изменился код для создания перед временной таблицей, а затем поместить данные внутри. Также проблема с последней строкой запроса 'table_C c ON b.ref_id_C = c.id_C', мне кажется, должна быть 'table_C c ON c.ref_id_B = b.id_B'. Таким образом, запрос работает, но данные, скопированные в таблице_C, неправильно относятся к таблице_B –

+0

Здесь запрос, который я использовал, разделен, чтобы избежать ограничения символа комментария –

+0

'drop table if exists table_a_copy; создать таблицу temp table_a_copy ("old_id" integer, "new_id" integer); с new_id_a как (insert into table_a (data_a) (выберите data_a из таблицы_a, где id_a = '1'), возвращающий id_a) insert into table_a_copy выберите '1' :: integer как old_id, (выберите * from new_id_a) как new_id; вставки в TABLE_B (ref_id_a, Данные) выберите cp.new_id, b.data_b из table_a_copy сП внутреннего соединение TABLE_B б на b.ref_id_a = cp.old_id; '' –

0

Вот мой последний запрос после испытаний, которые я сделал. Мне кажется, работает отлично, но я думаю, что она должна быть заменена более простым методом
Пожалуйста, добавьте свое мнение или исправление, благодаря

drop table if exists table_old_id_a; 
drop table if exists table_new_id_a; 
drop table if exists table_joined_old_new_id_a; 
-- 3 table 
-- 1st with old IDs and an arbitrary column to use to join 
-- 2nd with new IDs after insert; you just need the ID to avoid that other use the same ID, insert only minimum data 
-- 3rd is a table where you join old and new IDs using the join_column sequence 
-- after this you must update table_a with all the data you need, but you keep references in temp table table_joined_old_new_id_a 
create temp table table_old_id_a ("join_column" serial, "old_id" integer); 
create temp table table_new_id_a ("join_column" serial, "new_id" integer); 
create temp table table_joined_old_new_id_a ("old_id" integer, "new_id" integer); 
insert into table_old_id_a (old_id) select id_a from table_a where id_a='1'; 
with new_id_a as 
(insert into table_a (data_a) (select 'Copy of ' || data_a from table_a where id_a='1') returning id_a) 
insert into table_new_id_a (new_id) select id_a from new_id_a; 
insert into table_joined_old_new_id_a select table_old_id_a.old_id, table_new_id_a.new_id from table_old_id_a, table_new_id_a where table_old_id_a.join_column=table_new_id_a.join_column; 
-- then update the table with all the data 
with t_update_a as (select data_a, new_id, data_a2 from table_a t_old_id, table_joined_old_new_id_a where t_old_id.id_a=table_joined_old_new_id_a.old_id) 
update table_a set 
data_a=(select data_a from t_update_a where table_a.id_a=t_update_a.new_id), 
data_a2=(select data_a2 from t_update_a where table_a.id_a=t_update_a.new_id) 
where table_a.id_a in (select new_id from table_joined_old_new_id_a); 
-- table B data 
drop table if exists table_old_id_b; 
drop table if exists table_new_id_b; 
drop table if exists table_joined_old_new_id_b; 
create temp table table_old_id_b ("join_column" serial, "old_id" integer); 
create temp table table_new_id_b ("join_column" serial, "new_id" integer); 
create temp table table_joined_old_new_id_b ("old_id" integer, "new_id" integer); 
insert into table_old_id_b (old_id) select id_b from table_b where ref_id_a in (select old_id from table_old_id_a); 
with new_id_b as 
(insert into table_b (data_b) (select 'Copy of ' || data_b from table_b, table_old_id_a where table_old_id_a.old_id=table_b.ref_id_a) returning id_b) 
insert into table_new_id_b (new_id) select id_b from new_id_b; 
insert into table_joined_old_new_id_b select table_old_id_b.old_id, table_new_id_b.new_id from table_old_id_b, table_new_id_b where table_old_id_b.join_column=table_new_id_b.join_column; 
-- then update the table with all the data 
with t_update_b as 
(select data_b, new_id, ref_id_a from table_b t_old_id, table_joined_old_new_id_b where t_old_id.id_b=table_joined_old_new_id_b.old_id) 
update table_b set 
ref_id_a=(select table_joined_old_new_id_a.new_id from table_joined_old_new_id_a, t_update_b where table_joined_old_new_id_a.old_id=t_update_b.ref_id_a and table_b.id_b=t_update_b.new_id), 
data_b=(select data_b from t_update_b where table_b.id_b=t_update_b.new_id) 
where table_b.id_b in (select new_id from table_joined_old_new_id_b); 
-- table C data 
drop table if exists table_old_id_c; 
drop table if exists table_new_id_c; 
drop table if exists table_joined_old_new_id_c; 
create temp table table_old_id_c ("join_column" serial, "old_id" integer); 
create temp table table_new_id_c ("join_column" serial, "new_id" integer); 
create temp table table_joined_old_new_id_c ("old_id" integer, "new_id" integer); 
insert into table_old_id_c (old_id) select id_c from table_c where ref_id_b in (select old_id from table_old_id_b); 
with new_id_c as 
(insert into table_c (data_c) (select 'Copy of ' || data_c from table_c, table_old_id_b where table_old_id_b.old_id=table_c.ref_id_b) returning id_c) 
insert into table_new_id_c (new_id) select id_c from new_id_c; 
insert into table_joined_old_new_id_c select table_old_id_c.old_id, table_new_id_c.new_id from table_old_id_c, table_new_id_c where table_old_id_c.join_column=table_new_id_c.join_column; 
-- then update the table with all the data 
with t_update_c as 
(select data_c, new_id, ref_id_b from table_c t_old_id, table_joined_old_new_id_c where t_old_id.id_c=table_joined_old_new_id_c.old_id) 
update table_c set 
ref_id_b=(select table_joined_old_new_id_b.new_id from table_joined_old_new_id_b, t_update_c where table_joined_old_new_id_b.old_id=t_update_c.ref_id_b and table_c.id_c=t_update_c.new_id), 
data_c=(select data_c from t_update_c where table_c.id_c=t_update_c.new_id) 
where table_c.id_c in (select new_id from table_joined_old_new_id_c); 
-- last drop the temp tables 
drop table if exists table_old_id_a; 
drop table if exists table_new_id_a; 
drop table if exists table_joined_old_new_id_a; 
drop table if exists table_old_id_b; 
drop table if exists table_new_id_b; 
drop table if exists table_joined_old_new_id_b; 
drop table if exists table_old_id_c; 
drop table if exists table_new_id_c; 
drop table if exists table_joined_old_new_id_c; 
-- Finish! 
+0

Во время моего теста я добавляю столбец (data_a2) в таблицу_A, чтобы иметь больше данных для проверки правильной копии, поэтому он отличается от исходной схемы I отправил –