pl / sql中的嵌套表元素赋值

时间:2014-09-02 16:58:37

标签: collections plsql oracle11g

我在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循环”。

1 个答案:

答案 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