Мне нужно написать процедуру оракула pl / sql для удаления данных из нескольких таблиц. Критерии выбора
данные для удаления различны для каждой таблицы.
Для простоты, если у меня есть 3 таблицы, для каждой таблицы будет один запрос на выборку. т.е.
select id from table_a where product_type='A';
select name from table_b where category='student';
select phone_name from table_c where name='nokia';
Пара правил
- I can only delete 1000 records at a time for each table.
- I should issue a commit after every 1000 records
- Each row is processed first before deleting (in all tables)
Самое простое решение - иметь что-то вроде этого
commit_limit:=1000;
counter:=0;
recordsDeleted:=0;
For i in (select rowid,id from table_a where product_type='A') loop
Delete from table_a where rowid=i.rowid;
recordsDeleted:=SQL%rowcount;
counter:=counter++;
if(counter>=commit_limit) then
commit;
counter:=0;
>log to file that commit has been issued.
end if;
End loop;
counter:=0;
recordsDeleted:=0;
For i in (select rowid,name from table_b where category='student') loop
Delete from table_b where rowid=i.rowid;
recordsDeleted:=SQL%rowcount;
counter:=counter++;
if(counter>=commit_limit) then
commit;
counter:=0;
>log to file that commit has been issued.
end if;
End loop;
counter:=0;
recordsDeleted:=0;
For i in (select rowid,phone_name from table_c where name='nokia') loop
Delete from table_c where rowid=i.rowid;
recordsDeleted:=SQL%rowcount;
counter:=counter++;
if(counter>=commit_limit) then
commit;
counter:=0;
>log to file that commit has been issued and log value of 'recordsDeleted'.
end if;
End loop;
> log to file total records deleted.
Как видите, много повторений. Я хотел бы использовать процедуру, где я могу
укажите имя таблицы и запрос для использования в качестве критерия выбора.
Я думаю, что если бы не было критериев выбора и не было обработки для каждой строки перед удалением, это был бы простой случай построения динамического оператора SQL и использования выполнения немедленно для выполнения удаления.
Я хочу иметь процедуру / функцию, подобную этой ниже, и вызывать ее для каждой таблицы. (то есть 3 раза для приведенных выше примеров)
function delete_by_colid (table_name in varchar(35), column_name in varchar(150), select_criteria in varchar(200)) return number
Is
begin
counter:=0;
recordsDeleted:=0;
For i in (<<<select_criteria>>>) loop
Delete from <<<table_name>>> where <<<column_name>>>=i.rowid;
recordsDeleted:=SQL%rowcount;
counter:=counter++;
if(counter>=commit_limit) then
commit;
counter:=0;
>log to file that commit has been issued and log value of 'recordsDeleted'.
end if;
End loop;
return recordsDeleted;
End;
Проблема, с которой я столкнулся, не уверена в следующем
- Как включить select_criteria в цикл for? Будет ли работать явный курсор вместо этого? Как бы я определил это динамически?
- Как мне решить, какие размеры подходят для table_name и особенно для select_criteria, когда они передаются в функцию?
- Если я использую execute немедленно, чтобы выполнить динамически построенный оператор SQL. Как я могу получить значение sql% rowcount?
Заранее спасибо
Редактировать
Процесс, над которым я работаю, будет частью пакетного задания, которое будет выполняться в одночасье. Пакетное задание будет обрабатывать миллионы строк, а это может занять несколько часов.
Существуют и другие более важные процессы deamon, которые будут выполняться одновременно. Это означает, что процесс, который удаляет строки, должен быть защищен от блокировки таблиц / строк в результате удаления. Для этого мы намерены отправить процесс в спящий режим на несколько секунд после каждой фиксации, чтобы другие процессы могли продолжаться. Это означает, что я не могу просто удалить, используя один оператор «DELETE».