Oracle 未通过过程执行获得正确的输出
我正在为下表(示例表)编写一个递归过程: 考虑每个列都有VARCHAR2数据类型:Oracle 未通过过程执行获得正确的输出,oracle,plsql,Oracle,Plsql,我正在为下表(示例表)编写一个递归过程: 考虑每个列都有VARCHAR2数据类型: PARENT_DATA CHILD_DATA PARENT_VERSION CHILD_VERSION ---------------------------------------------------------------- 20-10 40-01 -A11 -A11 20-10 40-02 -A11 -A11
PARENT_DATA CHILD_DATA PARENT_VERSION CHILD_VERSION
----------------------------------------------------------------
20-10 40-01 -A11 -A11
20-10 40-02 -A11 -A11
20-10 40-03 -A11 -A11
20-10 80-10 -A11 -A11
20-10 81-10 -A11 -A11
80-10 40-100 -A11 -A11
80-10 40-101 -A11 -A11
80-10 40-102 -A11 -A11
我需要编写一个递归过程,这样对于给定的父级数据,如果子级数据以“40”开头,那么它将被打印出来。
如果子_数据以“80”开头,则将递归调用该过程。
最终输出如下所示:
PARENT_DATA CHILD_DATA PARENT_VERSION CHILD_VERSION
---------------------------------------------------
20-10 40-01 -A11 -A11
20-10 40-02 -A11 -A11
20-10 40-03 -A11 -A11
80-10 40-100 -A11 -A11
80-10 40-101 -A11 -A11
80-10 40-102 -A11 -A11
我尝试了使用游标的递归过程调用:
代码如下:
create or replace procedure proc_repeat(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
open cur_data;
loop
fetch cur_data
into v_parent_Data,v_data,v_data_VERSION;
exit when cur_data%notfound;
IF V_DATA LIKE '40-%' THEN
OUT_CHILD:=V_DATA;
OUT_CHILD_VERSION:=v_data_VERSION;
ELSIF V_DATA LIKE '80-%' THEN
v_data_RECUR:=V_DATA;
v_data_RECUR_VERSION:=v_data_VERSION;
proc_repeat(v_data_RECUR, v_data_RECUR_VERSION,
out_child, OUT_CHILD_VERSION);
END IF;
end loop;
close cur_Data;
end;
预期结果是:
CHILD_DATA
-----------
40-01
40-02
40-03
40-100
40-101
40-102
但我只得到“40-102”
DECLARE
A VARCHAR2(50):='20-10';
B VARCHAR2(50):='-A11';
C VARCHAR2(50);
D VARCHAR2(50);
BEGIN
proc_repeat(A,B,C,D);
DBMS_OUTPUT.PUT_LINE(C);
END;
让我们通过添加一些DBMS_OUTPUT.PUT_行调用来创建过程的插入指令的版本。这将看起来像:
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\u CHILD
,或者打印出来。因此,让我们更改插入指令的版本,将光标返回的值累加到OUT\u 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进行递归调用,此时它们消失了!啊!发生什么事了
关于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
最后,得到了正确的结果
所以,记住——当事情不起作用时,试着打印出中间结果,这样你就可以看到发生了什么
您打印任何内容的唯一时间是在匿名块中,该块会对您的过程进行第一次调用,因此当然只输出一行。也许您还需要从过程内部打印一些内容。那么获得预期输出的可能方法是什么呢?在过程中调用
dbms\u output
。要准确地说出从哪里读到它有点困难。但是,输出的目的是什么?一般来说,您的问题是如何添加调试消息吗?您在\u parent中输入20-10
作为的参数,但希望获得80-10