Как указывало @EdStevens, вы не можете избежать обработки курсоров. Но вы можете избежать зацикливания структуры курсора внутри курсора. И неявный курсор открытия и закрытия для внутреннего. Запросы объединяются в простое соединение, а затем собираются в одну коллекцию. Для этого я создал RECORD, который будет содержать как номер счета, так и номер карты; затем коллекция этой записи. Затем курсор массово собирается в коллекцию. Ваш исходный код позволяет обрабатывать до 100000 карт, и хотя я являюсь поклонником массового сбора (при необходимости), я не поклонник заполнения памяти, поэтому я ограничиваю количество строк массового сбора для каждой выборки. К сожалению, здесь вводится конструкция al oop -within-l oop, но наказание не так велико, как у конструкции курсор внутри курсора. Ниже приведен результат.
create or replace procedure blokiraj_proc (core_cust_id varchar2) as
type acct_card_r
is record(
acct_num test_kartice.rbs_acct_num%type
, card_num test_kartice.card_num%type
);
type acct_card_array is table of acct_card_r;
acct_card_list acct_card_array;
k_acct_card_buffer_limit constant integer := 997;
cursor c_acct_card(c_cust_id varchar2) is
select r.foracid
, k.card_num
from test_racuni r
left join test_kartice k
on (k.rbs_acct_num = r.foracid)
where r.cif_id = c_cust_id
order by r.foracid
, k.card_num;
begin
dbms_output.enable (buffer_size => null); -- enable dbms_output with size unlimited
open c_acct_card(core_cust_id);
loop
fetch c_acct_card
bulk collect
into acct_card_list
limit k_acct_card_buffer_limit;
for i in 1 .. acct_card_list.count
loop
dbms_output.put (acct_card_list(i).acct_num || ' ==> ');
if acct_card_list(i).card_num is not null
then
dbms_output.put_line (acct_card_list(i).card_num);
blokiraj_karticu (acct_card_list(i).card_num);
else
dbms_output.put_line ('No card for this account');
end if;
end loop;
-- exit buffer fetch when current buffeer is not full. As that means all rows
-- from cursor have been fetched/processed.
exit when acct_card_list.count < k_acct_card_buffer_limit;
end loop;
close c_acct_card;
end blokiraj_proc;
Ну, это просто другой подход. Если тебе будет лучше, отлично. Я также хочу повторить и расширить предупреждение Эда Стивенса о запуске этого из триггера. Если одна из таблиц здесь является таблицей, по которой сработал триггер, вы все равно получите исключение изменяющейся таблицы - вы не можете просто спрятать ее за процедурой. И даже если не много циклов для триггера.