我有一个名为“ test_table”的表。它有两个名为“父母”和“孩子”的栏,如下所示: 假设两列都是Varchar2类型。
PARENT CHILD
---------------------
50-100 10-001
50-100 10-002
50-100 10-003
50-100 11-100
50-100 11-101
11-100 10-100
11-100 10-101
11-100 10-102
我需要编写一种递归过程,如果给定父母的孩子以“ 10”开头,那么它将被打印出来。 如果子值以“ 11”开头,则将为每个以11开头的子值递归调用该过程。 下面是所需的示例输出:
CHILD
--------------
10-001
10-002
10-003
10-100
10-101
10-102
这是示例过程:
create or replace type type_test2 as table of varchar2(2000);
create or replace procedure test_proc
(parent_data in type_test2,child_data out type_test2)
as
v_out type_test2:=type_test2();
begin
child_data:=type_test2();
select child
bulk collect into v_out
from test_table
where parent in(select * from table(parent_data));
for i in 1..v_out.count loop
child_data.extend(i);
v_out.extend(i);
if v_out(i) like '10-%' then
child_data(i):=v_out(I);
elsif v_out(i) like '11-%' then
test_proc(v_out,child_data);
end if;
end loop;
end;
/
执行上述过程:
declare
a type_test2:=type_test2('50-100');
b type_test2:=type_test2();
begin
test_proc(a,b);
for i in 1..b.count loop
dbms_output.put_line(b(I));
end loop;
end;
/
但是我只得到5个子值,而不是6个值。缺少“ 10-100”。
Child
---------------
10-102
10-101
10-003
10-002
10-001
请帮助我获得正确的输出。
答案 0 :(得分:0)
不要递归调用该过程;而是使用单个分层查询:
过程:
CREATE PROCEDURE test_proc (
i_parent IN test_table.parent%TYPE,
o_children OUT type_test2
)
AS
BEGIN
SELECT CHILD
BULK COLLECT INTO o_children
FROM test_table
WHERE CHILD like '10-%'
START WITH parent = i_parent
CONNECT BY NOCYCLE
PRIOR child = parent
AND PRIOR child LIKE '11-%';
END;
/
执行:
DECLARE
b type_test2:=type_test2();
BEGIN
test_proc( '50-100', b );
FOR i IN 1..b.COUNT LOOP
DBMS_OUTPUT.PUT_LINE( b(i) );
END LOOP;
END;
/
输出:
10-001 10-002 10-003 10-100 10-101 10-102
备用:
您甚至不需要一个过程,并且可以在一个查询中完成所有操作:
SELECT CHILD
FROM test_table
WHERE CHILD like '10-%'
START WITH parent = '50-100'
CONNECT BY NOCYCLE
PRIOR child = parent
AND PRIOR child LIKE '11-%';
哪个输出:
| CHILD | | :----- | | 10-001 | | 10-002 | | 10-003 | | 10-100 | | 10-101 | | 10-102 |
为什么递归过程没有得到正确的输出。
每次使用BULK COLLECT INTO
时,它都会重新初始化要输出到的集合并覆盖以前的值。您需要BULK COLLECT INTO
一个不同的集合,然后如果想要保留以前的值,则将两者合并。
类似的东西:
CREATE OR REPLACE PROCEDURE test_proc(
parent_data IN type_test2,
child_data OUT type_test2
)
AS
v_to_search type_test2;
v_search_results type_test2;
i PLS_INTEGER;
BEGIN
SELECT child
BULK COLLECT INTO child_data
FROM test_table
WHERE parent MEMBER OF parent_data
AND child LIKE '10-%';
SELECT child
BULK COLLECT INTO v_to_search
FROM test_table
WHERE parent MEMBER OF parent_data
AND child LIKE '11-%';
IF v_to_search.COUNT = 0 THEN
RETURN;
END IF;
test_proc( v_to_search, v_search_results );
i := child_data.COUNT;
child_data.EXTEND( v_search_results.COUNT );
FOR j IN 1 .. v_search_results.COUNT LOOP
child_data(i+j) := v_search_results(j);
END LOOP;
END;
/
但是,如果您的数据中存在一个循环,则可能陷入无限循环。上面的分层查询将检测循环并停止迭代(或者,如果您删除NOCYCLE
关键字,则会引发异常)。
db <>提琴here