Вы можете увидеть, что происходит, добавив несколько отладок:
create sequence s42;
set serveroutput on
declare
cursor c is
select s42.nextval from dual;
n pls_integer;
begin
open c;
for i in 1..5 loop
fetch c into n;
dbms_output.put_line('i: ' || i
|| '; n: ' || n
|| '; found: ' || case when c%found then 'true' else 'false' end);
end loop;
close c;
end;
/
i: 1; n: 1; found: true
i: 2; n: 1; found: false
i: 3; n: 1; found: false
i: 4; n: 1; found: false
i: 5; n: 1; found: false
PL/SQL procedure successfully completed.
Вы открываете курсор только один раз, и курсор возвращает только одну строку.Итак, первая выборка находит значение (c%found
верно).Вторая и последующие выборки не находят строки, поскольку однострочный набор результатов уже исчерпан.
Короче говоря, nextval
выполняется только один раз, поэтому последовательность увеличивается только один раз.
Во второй версии весь запрос повторно выполняется внутри цикла, поэтому nextval
вызывается несколько раз, и, следовательно, последовательность также увеличивается несколько раз.
Вы увидите то же самоеесли вы снова открыли курсор внутри цикла:
declare
cursor c is
select s42.nextval from dual;
n pls_integer;
begin
for i in 1..5 loop
open c;
fetch c into n;
dbms_output.put_line('i: ' || i
|| '; n: ' || n
|| '; found: ' || case when c%found then 'true' else 'false' end);
close c;
end loop;
end;
/
i: 1; n: 2; found: true
i: 2; n: 3; found: true
i: 3; n: 4; found: true
i: 4; n: 5; found: true
i: 5; n: 6; found: true
, но на самом деле это более длинный и более сложный способ сделать select ... into
, поскольку он может возвращать только одну строку за раз.