Как вставить в две таблицы одновременно - PullRequest
2 голосов
/ 17 ноября 2011

Я надеюсь, что смогу объяснить это правильно. Мне нужно вставить данные в две таблицы БД. Эти данные уже хранятся в двух других таблицах, но их необходимо перенести. Для упрощения скажем вот мои исходные таблицы:

папка с колонками folderid, foldername

ссылка с колонками linkid, url и folderid

И мои таблицы назначения:

new_folder с столбцами folderid, foldername

new_link с колонками linkid, url и folderid

Есть и другие столбцы, но они не важны. Моя проблема в том, что, кто бы ни настраивал исходную базу данных, использовал генератор случайных чисел в java для создания идентификаторов папок и ссылок, и эти числа - полный мусор. Их необходимо заменить числом, сгенерированным последовательностью, которая существует в БД.

Так что мне нужно одно утверждение, которое делает что-то вроде следующего:

insert into new_folder(folderid, foldername), new_link(linkid, url, folderid)
values (select seq_folder_id.nextval, foldername, seq_link_id.nextval, url, seq_folder_id.currval from folder, link where folder.folderid = link.folderid).

Может быть несколько ссылок, связанных с папкой. В таблице папок содержится 200 тыс. Строк и в 10 раз больше, чем в таблице ссылок, поэтому мне нужен какой-то сценарий, который будет запускать и извлекать все папки и создавать новые записи с новой последовательностью в качестве идентификатора. Это само по себе было бы хорошо, но если я просто сделаю это, у меня не будет возможности сопоставить ссылки на папки после изменения идентификатора, если я не сделаю это в одном операторе, если это имеет смысл.

1 Ответ

5 голосов
/ 17 ноября 2011

Вот хороший урок по многостольным вставкам:

http://www.oracle -developer.net / display.php? ID = 209

Базовая структура:

INSERT ALL|FIRST
   [WHEN condition THEN] INTO target [VALUES]
   [WHEN condition THEN] INTO target [VALUES]
   ...
   [ELSE] INTO target [VALUES]
SELECT ...
FROM   source_query;

Возможно, вы захотите реструктурировать исходный подзапрос, чтобы создать столбец, в котором указана первая строка для каждого имени папки, которую вы затем можете использовать в условиях when, чтобы вставить только одну строку в папку в таблицу папок, а затем все строки в таблица ссылок. Вам также нужно будет перенастроить способ создания идентификаторов, чтобы у вас был одинаковый folderID для каждой строки ссылки. Другими словами, раз вы выучили агрегатные функции!

Пример: посмотрите на этот запрос и посмотрите, поможет ли он вам разобраться (подсказка, folder_rank может стать основой для folder_id, и как group_rank может использовать выражение when для определения вставки папки)

select dense_rank() over (order by foldername) as folder_rank,
       rank() over (parition by foldername order  by url) as group_rank
     , foldername
     , seq_link_id.nextval
     , url 
from folder, link 
where folder.folderid = link.folderid

С другой стороны, посмотрите на это в виде фрагмента pl / sql, а не чистого SQL:

declare
  l_new_folder_id new_folder.folder_id%type;
begin
   for folder_Rec in (select folder_id, foldername from folder)
   loop
      insert into new_folder (folder_id, folder_name) 
      values ( seq_folder_id.nextval, folder_Rec.folder_name) 
      returning folder_id into l_new_folder_id;

      for link_rec in (select url from link where folder_id = folder_rec.folder_id)
          insert into new_link (link_id, folder_id, url) 
          values (seq_link_id.nextval, l_new_folder_id, link_rec.url);
      end loop;
    end loop;
    commit;
end;

Есть несколько способов обрезать эту кошку, и сложный SQL может быть не лучшим вариантом для новичка. Кроме того, проверьте исходные данные - если у вас есть папки, у которых нет ссылок, то подход чистого SQL также должен включать внешнее объединение, а не текущее определение, если вы хотите, чтобы папки без ссылок были вставлены. Решение PL / Sql уже справится с этим сценарием.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...