I hope I am able to explain this properly. I need to insert data into two DB tables. This data is already stored in two other tables but needs to be migrated. To simplify things lets say here are my source tables:
folder with columns folderid, foldername
link with columns linkid, url and folderid
And my destination tables are:
new_folder with columns folderid, foldername
new_link with columns linkid, url and folderid
There are other columns also but they are not important. My problem is that whoever setup the original database used a random number generator in java to create the folder and link ids and these numbers are complete garbage. They need to be replaced with a number generated by a sequence which exists in the DB.
So what I need is one statement that does something like the following:
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).
There could be multiple links associated with the folder. There are 200k rows in the folder table and 10 times that in the link table so I need some sort of a script that will run and pull out all folders and create new entries with the new sequence as the ID. That on its own would be fine but if I just do that then I have no way of mapping the links to the folders once the ID is changed unless I do it in the one statement if that makes sense.
Here is a good tutorial on multi-table inserts:
http://www.oracle-developer.net/display.php?id=209
The basic structure is:
INSERT ALL|FIRST
[WHEN condition THEN] INTO target [VALUES]
[WHEN condition THEN] INTO target [VALUES]
...
[ELSE] INTO target [VALUES]
SELECT ...
FROM source_query;
You will probably want to restructure your source subquery to create a column that indicates the first row for each foldername that you can then use in the when conditions to only insert one row per folder to the folder table, and then all rows to the link table. You will also have to re-jig how you are generating the IDs so that you have the same folderID for each link row. In other words, time you learned aggregate functions!
Example: look at this query and see if it would help you figure it out (hint, folder_rank can become the basis for the folder_id, and how group_rank could drive a when clause to figure out the folder insert)
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
Alternately, look at doing this in a chunk of pl/sql rather than pure 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;
There are several ways to skin this cat, and complex SQL may not be the best option for a beginner. Also, check your source data - if you have folders that do not have any links then the pure SQL approach will also have to incoporate an outer join rather than the current definition if you want the link-less folders to be inserted. The PL/Sql solution will already handle that scenario.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.