Копирование записей в таблице с самообращающимися идентификаторами - PullRequest
0 голосов
/ 22 января 2020

У меня есть таблица с записями, которые могут ссылаться на другую строку в той же таблице, поэтому между строками в одной и той же таблице есть отношения родитель-потомок.

Я пытаюсь создать такую ​​же данные для другого пользователя, чтобы они могли видеть и управлять своей собственной версией этой структуры через веб-интерфейс, где эти строки отображаются в виде дерева.

Проблема заключается в том, что при групповой вставке этих данных путем изменения только user_id, я потерять связь между строками, потому что значения parent_id будут недопустимыми для этих новых записей, и они также должны быть обновлены с помощью вновь созданных идентификаторов.

Вот что я пробовал: (не работает)

  • Итерировать по main_table
  • копировать и вставлять значения * stati c после каждого
  • делать еще одну вставку во временную таблицу для хранения старых и новых идентификаторов
  • обновить старые parent_ids новыми идентификаторами после того, как l oop заканчивается

Моя попытка сделать это (последний шаг здесь не включен)

create or replace function test_x()
returns void as
$BODY$
declare
r RECORD;
userId int8;
rowPK int8;
begin
    userId := (select 1)
    create table if not exists id_map (old_id int8, new_id int8);
    create table if not exists temp_table as select * from main_table;
    for r in select * from temp_table
    loop
        rowPK := insert into main_table(id, user_id, code, description, parent_id)
        values(nextval('hibernate_sequence'), userId, r.code, r.description, r.parent_id) returning id;
        insert into id_map (old_id, new_id) values (r.id, rowPK);
    end loop;
end
$BODY$
language plpgsql;
* 102 1 * Моя PostgreSQL версия 9.6.14.

DDL ниже для тестирования.

create table main_table(
    id bigserial not null,
    user_id int8 not null,
    code varchar(3) not null,
    description varchar(100) not null,
    parent_id int8 null,
    constraint mycompkey unique (user_id, code, parent_id),
    constraint mypk primary key (id),
    constraint myfk foreign key (parent_id) references main_table(id)
);
insert into main_table (id, user_id, code, description, parent_id)
values(0, 0, '01', 'Root row', null);
insert into main_table (id, user_id, code, description, parent_id)
values(1, 0, '001', 'Child row 1', 0);
insert into main_table (id, user_id, code, description, parent_id)
values(2, 0, '002', 'Child row 2', 0);
insert into main_table (id, user_id, code, description, parent_id)
values(3, 0, '002', 'Grand child row 1', 2);

Как написать процедуру для выполнения sh this?

Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 24 января 2020

Похоже, ваша задача копировать все данные для данного пользователя другому, сохраняя при этом иерархические отношения в новых строках. Следующее выполняет это. Начинается создание новой копии существующих строк с новым user_id, включая старую строку parent_id. Это будет пользователь на следующем шаге (обновление). CTE логически начинается с новых строк, которые имеют parent_id и присоединяется к старой родительской строке. Отсюда он соединяется со старой родительской строкой и новой родительской строкой, используя код и описание. В этот момент у нас есть новый идентификатор вместе с новым родителем is. В этот момент просто обновите эти значения. На самом деле для обновления CTE нужно только выбрать эти два столбца, но я оставил промежуточные столбцы, так что вы проследите, если вы будете sh.

create or replace function copy_user_data_to_user( 
                           source_user_id bigint
                         , target_user_id bigint
                         )
returns void 
language plpgsql
as $$
begin
    insert into main_table ( user_id,code, description, parent_id )
           select target_user_id, code, description, parent_id
             from main_table 
            where user_id = source_user_id ;

    with n_list as 
        (select mt.id, mt.code, mt.description, mt.parent_id
              , mtp.id p_id,mtp.code p_code,mtp.description p_des
              , mtc.id c_id, mtc.code c_code, mtc.description c_description 
           from main_table mt
           join main_table mtp on mtp.id = mt.parent_id
           join main_table mtc on (    mtc.user_id = target_user_id
                                   and mtc.code    = mtp.code
                                   and mtc.description = mtp.description
                                  )
          where mt.parent_id is not null
            and mt.user_id = target_user_id
        )
    update main_table mt
       set parent_id = n_list.c_id
      from n_list
     where mt.id = n_list.id;

    return;
 end ; 
$$; 

-- test 
select * from copy_user_data_to_user(0,1);
select * from main_table;
0 голосов
/ 30 января 2020

CREATE TABLE 'имя таблицы, которую вы хотите создать' SELECT * FROM myset

, но имя новой таблицы и столбца myset должно совпадать, и вы также можете использовать вместо * к имени столбца, но имя столбца существует в новой таблице, в противном случае получаются ошибки

...