我在pl / sql嵌套表中的要求如下:
我声明了一个嵌套的表集合类型,并根据表中的查找填充元素。 如果查找产生多个行(代码的多个值),则在嵌套表中添加所有这些多个值并继续。这是我被困的地方。 我无法在异常中增加父计数器“indx”来处理这些多行。由于我不是,它只将最新数据存储在嵌套表中,而不是全部存储。
declare
TYPE final_coll_typ IS TABLE OF varchar2(100);
l_final_coll final_coll_typ;
MULTI_FETCH EXCEPTION;
PRAGMA EXCEPTION_INIT(MULTI_FETCH, -1422); -- this is an ora error for exact fetch returns more than the required number of rows
begin
for indx in 1..<count> loop
<some processing logic here>
select code into l_final_coll(indx) from lookup_tbl where <some filter>;
exception
when MULTI_FETCH then
for p in (select code from lookup_tbl where <some filter>)
loop
l_final_coll(indx) := p.code;
dbms_output.put_line(l_final_coll(indx));
end loop;
continue; -- this is for further processing after the loop
end loop;
end;
让我们说,计数器indx的第一次迭代只为代码生成了一行数据。它存储在l_final_coll(indx)中。 让我们说主要for循环的indx i的下一次迭代会为代码生成2行值。我的想法是捕获异常(ORA-01422)并继续在现有的嵌套表中添加这两个代码值。
因此,实际上,我的嵌套表现在应该在其元素中有3个代码值。但是,目前,我只能让它填充其中的两个(从第一次运行的单个值和从下一个运行的最新值)
如何实现这一目标,我们将不胜感激。
PS:尝试操纵计数器变量indx和p。但是,显然pl / sql不允许它用于“for循环”。
答案 0 :(得分:2)
你根本不需要做一个选择,只需使用游标循环开始,然后附加到集合(你必须初始化):
declare
type final_coll_typ is table of varchar2(100);
l_final_coll final_coll_typ;
begin
l_final_coll := final_coll_typ();
for indx in 1..<count> loop
<some processing logic here>
for p in (select code from lookup_tbl where <some filter>) loop
l_final_coll.extend(1);
l_final_coll(l_final_coll.count) := p.code;
end loop;
end loop;
dbms_output.put_line('Final size: ' || l_final_coll.count);
end;
/
对于找到但光标的每一行,集合被扩展一个(效率不高),并且光标值放在最后一个空行中;这是从当前count
找到的。
作为演示,如果我创建一个具有重复值的虚拟表:
create table lookup_tbl(code varchar2(100));
insert into lookup_tbl values ('Code 1');
insert into lookup_tbl values ('Code 2');
insert into lookup_tbl values ('Code 2');
insert into lookup_tbl values ('Code 3');
...然后使用特定的计数器和过滤器:
declare
type final_coll_typ is table of varchar2(100);
l_final_coll final_coll_typ;
begin
l_final_coll := final_coll_typ();
for indx in 1..3 loop
for p in (select code from lookup_tbl where code = 'Code ' || indx) loop
l_final_coll.extend(1);
l_final_coll(l_final_coll.count) := p.code;
end loop;
end loop;
dbms_output.put_line('Final size: ' || l_final_coll.count);
end;
/
......我明白了:
anonymous block completed
Final size: 4
作为一个稍微复杂的选项,您可以将所有匹配的数据批量收集到临时集合中,然后循环遍历该值以将这些值附加到真实集合中。类似的东西:
declare
type final_coll_typ is table of varchar2(100);
l_final_coll final_coll_typ;
l_tmp_coll sys.dbms_debug_vc2coll;
begin
l_final_coll := final_coll_typ();
for indx in 1..<count> loop
<some processing logic here>
select code bulk collect into l_tmp_coll from lookup_tbl where <some filter>;
for cntr in 1..l_tmp_coll.count loop
l_final_coll.extend(1);
l_final_coll(l_final_coll.count) := l_tmp_coll(cntr);
end loop;
end loop;
end;
/
可能有更快的方法来组合两个集合,但我不知道一个。批量收集必须是模式级别的集合类型,因此您无法使用本地final_coll_typ
。您可以创建自己的模式级类型,然后将其用于临时和最终集合变量;但我使用了内置的sys.dbms_debug_vc2coll
,其定义为table of varchar2(1000)
。
作为演示,使用与上面相同的表/数据,以及相同的特定计数和过滤器:
declare
type final_coll_typ is table of varchar2(100);
l_final_coll final_coll_typ;
l_tmp_coll sys.dbms_debug_vc2coll;
begin
l_final_coll := final_coll_typ();
for indx in 1..3 loop
select code bulk collect into l_tmp_coll
from lookup_tbl where code = 'Code ' || indx;
for cntr in 1..l_tmp_coll.count loop
l_final_coll.extend(1);
l_final_coll(l_final_coll.count) := l_tmp_coll(cntr);
end loop;
end loop;
dbms_output.put_line('Final size: ' || l_final_coll.count);
end;
/
......我再次得到:
anonymous block completed
Final size: 4