Давайте создадим инструментальную версию вашей процедуры, добавив несколько вызовов DBMS_OUTPUT.PUT_LINE.Это будет выглядеть так:
create or replace procedure proc_repeat_I1(in_parent in varchar2,
IN_VERSION IN VARCHAR2,
out_child out varchar2,
OUT_CHILD_VERSION OUT VARCHAR2)
as
v_parent_Data varchar2(50);
v_data varchar2(50);
v_data_VERSION varchar2(50);
v_data_RECUR varchar2(50);
v_data_RECUR_VERSION varchar2(50);
cursor cur_data is
select parent_data,child_data,child_version
from sample_table
where parent_data = in_parent AND
parent_version = IN_VERSION;
begin
DBMS_OUTPUT.PUT_LINE('PROC_REPEAT_I1 : START - IN_PARENT=' || IN_PARENT ||
' IN_VERSION=' || IN_VERSION ||
' OUT_CHILD=' || OUT_CHILD);
open cur_data;
loop
fetch cur_data
into v_parent_Data,v_data,v_data_VERSION;
exit when cur_data%notfound;
DBMS_OUTPUT.PUT_LINE('PROC_REPEAT_I1 : v_parent_Data=' || v_parent_Data ||
' v_data=' || v_data);
IF V_DATA LIKE '40-%' THEN
OUT_CHILD:=V_DATA;
OUT_CHILD_VERSION:=v_data_VERSION;
DBMS_OUTPUT.PUT_LINE('PROC_REPEAT_I1 : BLOCK 1 : OUT_CHILD = ' || OUT_CHILD);
ELSIF V_DATA LIKE '80-%' THEN
v_data_RECUR:=V_DATA;
v_data_RECUR_VERSION:=v_data_VERSION;
DBMS_OUTPUT.PUT_LINE('PROC_REPEAT_I1 : BLOCK 2 : OUT_CHILD = ' || OUT_CHILD ||
' V_DATA_RECUR = ' || V_DATA_RECUR);
proc_repeat_I(v_data_RECUR, v_data_RECUR_VERSION,
out_child, OUT_CHILD_VERSION);
END IF;
end loop;
close cur_Data;
DBMS_OUTPUT.PUT_LINE('PROC_REPEAT_I1 : EXIT');
end;
Когда мы запустим это, вы получите:
PROC_REPEAT_I1 : START - IN_PARENT=20-10 IN_VERSION=-A11 OUT_CHILD=
PROC_REPEAT_I1 : v_parent_Data=20-10 v_data=40-01
PROC_REPEAT_I1 : BLOCK 1 : OUT_CHILD = 40-01
PROC_REPEAT_I1 : v_parent_Data=20-10 v_data=40-02
PROC_REPEAT_I1 : BLOCK 1 : OUT_CHILD = 40-02
PROC_REPEAT_I1 : v_parent_Data=20-10 v_data=40-03
PROC_REPEAT_I1 : BLOCK 1 : OUT_CHILD = 40-03
PROC_REPEAT_I1 : v_parent_Data=20-10 v_data=80-10
PROC_REPEAT_I1 : BLOCK 2 : OUT_CHILD = 40-03 V_DATA_RECUR = 80-10
PROC_REPEAT_I1 : START - IN_PARENT=80-10 IN_VERSION=-A11 OUT_CHILD=
PROC_REPEAT_I1 : v_parent_Data=80-10 v_data=40-100
PROC_REPEAT_I1 : BLOCK 1 : OUT_CHILD = 40-100
PROC_REPEAT_I1 : v_parent_Data=80-10 v_data=40-101
PROC_REPEAT_I1 : BLOCK 1 : OUT_CHILD = 40-101
PROC_REPEAT_I1 : v_parent_Data=80-10 v_data=40-102
PROC_REPEAT_I1 : BLOCK 1 : OUT_CHILD = 40-102
PROC_REPEAT_I1 : EXIT
PROC_REPEAT_I1 : v_parent_Data=20-10 v_data=81-10
PROC_REPEAT_I1 : EXIT
40-102
Мы видим, что первый вызов процедуры из анонимного блока сделан, передавая'20-10'
в качестве родителя и '-A11'
в качестве родительской версии, а затем курсор перебирает '40-01
', '40-02'
и '40-03'
, пока не достигнет '80-10'
.Как только он достигает '80-20'
, он переходит ко второму блоку и рекурсивно вызывает себя, затем перебирает '40-100'
, '40-101'
и '40-102'
, как и ожидалось.
Так что же здесь не так?Ну ничего - кроме того, что нигде ваш код не заставляет значение из курсора либо накапливаться в OUT_CHILD
, либо печататься.Итак, давайте изменим нашу инструментальную версию, чтобы накапливать значения, возвращаемые курсором, в OUT_CHILD
:
create or replace procedure proc_repeat_I2(in_parent in varchar2,
IN_VERSION IN VARCHAR2,
out_child out varchar2,
OUT_CHILD_VERSION OUT VARCHAR2)
as
v_parent_Data varchar2(50);
v_data varchar2(50);
v_data_VERSION varchar2(50);
v_data_RECUR varchar2(50);
v_data_RECUR_VERSION varchar2(50);
cursor cur_data is
select parent_data,child_data,child_version
from sample_table
where parent_data = in_parent AND
parent_version = IN_VERSION;
begin
DBMS_OUTPUT.PUT_LINE('PROC_REPEAT : START - IN_PARENT=' || IN_PARENT ||
' IN_VERSION=' || IN_VERSION ||
' OUT_CHILD=' || OUT_CHILD);
open cur_data;
loop
fetch cur_data
into v_parent_Data,v_data,v_data_VERSION;
exit when cur_data%notfound;
DBMS_OUTPUT.PUT_LINE('PROC_REPEAT : v_parent_Data=' || v_parent_Data ||
' v_data=' || v_data);
IF V_DATA LIKE '40-%' THEN
OUT_CHILD := CASE
WHEN OUT_CHILD IS NULL THEN OUT_CHILD
ELSE OUT_CHILD || ', '
END || V_DATA;
OUT_CHILD_VERSION := CASE
WHEN OUT_CHILD_VERSION IS NULL THEN OUT_CHILD_VERSION
ELSE OUT_CHILD_VERSION || ', '
END || V_DATA_VERSION;
DBMS_OUTPUT.PUT_LINE('BLOCK 1 : OUT_CHILD = ' || OUT_CHILD);
ELSIF V_DATA LIKE '80-%' THEN
v_data_RECUR:=V_DATA;
v_data_RECUR_VERSION:=v_data_VERSION;
DBMS_OUTPUT.PUT_LINE('BLOCK 2 : OUT_CHILD = ' || OUT_CHILD ||
' V_DATA_RECUR = ' || V_DATA_RECUR);
proc_repeat_I2(v_data_RECUR, v_data_RECUR_VERSION,
out_child, OUT_CHILD_VERSION);
END IF;
end loop;
close cur_Data;
DBMS_OUTPUT.PUT_LINE('PROC_REPEAT : EXIT');
end;
Но это все же не дает правильного результата!Вот вывод:
PROC_REPEAT_I2 : START - IN_PARENT=20-10 IN_VERSION=-A11 OUT_CHILD=
PROC_REPEAT_I2 : v_parent_Data=20-10 v_data=40-01
PROC_REPEAT_I2 : BLOCK 1 : OUT_CHILD = 40-01
PROC_REPEAT_I2 : v_parent_Data=20-10 v_data=40-02
PROC_REPEAT_I2 : BLOCK 1 : OUT_CHILD = 40-01, 40-02
PROC_REPEAT_I2 : v_parent_Data=20-10 v_data=40-03
PROC_REPEAT_I2 : BLOCK 1 : OUT_CHILD = 40-01, 40-02, 40-03
PROC_REPEAT_I2 : v_parent_Data=20-10 v_data=80-10
PROC_REPEAT_I2 : BLOCK 2 : OUT_CHILD = 40-01, 40-02, 40-03 V_DATA_RECUR = 80-10
PROC_REPEAT_I2 : START - IN_PARENT=80-10 IN_VERSION=-A11 OUT_CHILD=
PROC_REPEAT_I2 : v_parent_Data=80-10 v_data=40-100
PROC_REPEAT_I2 : BLOCK 1 : OUT_CHILD = 40-100
PROC_REPEAT_I2 : v_parent_Data=80-10 v_data=40-101
PROC_REPEAT_I2 : BLOCK 1 : OUT_CHILD = 40-100, 40-101
PROC_REPEAT_I2 : v_parent_Data=80-10 v_data=40-102
PROC_REPEAT_I2 : BLOCK 1 : OUT_CHILD = 40-100, 40-101, 40-102
PROC_REPEAT_I2 : EXIT
PROC_REPEAT_I2 : v_parent_Data=20-10 v_data=81-10
PROC_REPEAT_I2 : EXIT
40-100, 40-101, 40-102
Здесь мы можем видеть, что родительские значения, по-видимому, накапливаются, пока мы не перейдем в блок 2 и не сделаем рекурсивный вызов PROC_REPEAT_I2, после чего ... ОНИ УХОДЯТ!AGGGHHHH!ЧТО ПРОИЗОШЛО?!?!?!?
Что ж, интересный факт о PL / SQL - когда вы вызываете подпрограмму с параметром OUT
, для параметра OUT в начале процедуры устанавливается значение NULL.Если вы хотите, чтобы значение, которое уже есть в аргументе процедуры, было сохранено, вам нужно определить аргумент как IN OUT
вместо OUT
.Итак, мы получаем нашу третью версию этой процедуры:
create or replace procedure PROC_REPEAT_I3(in_parent in varchar2,
IN_VERSION IN VARCHAR2,
out_child IN OUT varchar2,
OUT_CHILD_VERSION IN OUT VARCHAR2)
as
v_parent_Data varchar2(50);
v_data varchar2(50);
v_data_VERSION varchar2(50);
v_data_RECUR varchar2(50);
v_data_RECUR_VERSION varchar2(50);
cursor cur_data is
select parent_data,child_data,child_version
from sample_table
where parent_data = in_parent AND
parent_version = IN_VERSION;
begin
DBMS_OUTPUT.PUT_LINE('PROC_REPEAT_I3 : START - IN_PARENT=' || IN_PARENT ||
' IN_VERSION=' || IN_VERSION ||
' OUT_CHILD=' || OUT_CHILD);
open cur_data;
loop
fetch cur_data
into v_parent_Data,v_data,v_data_VERSION;
exit when cur_data%notfound;
DBMS_OUTPUT.PUT_LINE('PROC_REPEAT_I3 : v_parent_Data=' || v_parent_Data ||
' v_data=' || v_data);
IF V_DATA LIKE '40-%' THEN
OUT_CHILD := CASE
WHEN OUT_CHILD IS NULL THEN OUT_CHILD
ELSE OUT_CHILD || ', '
END || V_DATA;
OUT_CHILD_VERSION := CASE
WHEN OUT_CHILD_VERSION IS NULL THEN OUT_CHILD_VERSION
ELSE OUT_CHILD_VERSION || ', '
END || V_DATA_VERSION;
DBMS_OUTPUT.PUT_LINE('PROC_REPEAT_I3 : BLOCK 1 : OUT_CHILD = ' || OUT_CHILD);
ELSIF V_DATA LIKE '80-%' THEN
v_data_RECUR:=V_DATA;
v_data_RECUR_VERSION:=v_data_VERSION;
DBMS_OUTPUT.PUT_LINE('PROC_REPEAT_I3 : BLOCK 2 : OUT_CHILD = ' || OUT_CHILD ||
' V_DATA_RECUR = ' || V_DATA_RECUR);
proc_repeat_I3(v_data_RECUR, v_data_RECUR_VERSION,
out_child, OUT_CHILD_VERSION);
END IF;
end loop;
close cur_Data;
DBMS_OUTPUT.PUT_LINE('PROC_REPEAT_I3 : EXIT');
end;
, и результат этой версии выглядит следующим образом:
PROC_REPEAT_I3 : START - IN_PARENT=20-10 IN_VERSION=-A11 OUT_CHILD=
PROC_REPEAT_I3 : v_parent_Data=20-10 v_data=40-01
PROC_REPEAT_I3 : BLOCK 1 : OUT_CHILD = 40-01
PROC_REPEAT_I3 : v_parent_Data=20-10 v_data=40-02
PROC_REPEAT_I3 : BLOCK 1 : OUT_CHILD = 40-01, 40-02
PROC_REPEAT_I3 : v_parent_Data=20-10 v_data=40-03
PROC_REPEAT_I3 : BLOCK 1 : OUT_CHILD = 40-01, 40-02, 40-03
PROC_REPEAT_I3 : v_parent_Data=20-10 v_data=80-10
PROC_REPEAT_I3 : BLOCK 2 : OUT_CHILD = 40-01, 40-02, 40-03 V_DATA_RECUR = 80-10
PROC_REPEAT_I3 : START - IN_PARENT=80-10 IN_VERSION=-A11 OUT_CHILD=40-01, 40-02, 40-03
PROC_REPEAT_I3 : v_parent_Data=80-10 v_data=40-100
PROC_REPEAT_I3 : BLOCK 1 : OUT_CHILD = 40-01, 40-02, 40-03, 40-100
PROC_REPEAT_I3 : v_parent_Data=80-10 v_data=40-101
PROC_REPEAT_I3 : BLOCK 1 : OUT_CHILD = 40-01, 40-02, 40-03, 40-100, 40-101
PROC_REPEAT_I3 : v_parent_Data=80-10 v_data=40-102
PROC_REPEAT_I3 : BLOCK 1 : OUT_CHILD = 40-01, 40-02, 40-03, 40-100, 40-101, 40-102
PROC_REPEAT_I3 : EXIT
PROC_REPEAT_I3 : v_parent_Data=20-10 v_data=81-10
PROC_REPEAT_I3 : EXIT
40-01, 40-02, 40-03, 40-100, 40-101, 40-102
Наконец, получаются правильные результаты.
Итак, помните - когда что-то не работает, попробуйте распечатать промежуточные результаты, чтобы вы могли видеть, что происходит.
dbfiddle здесь