【问题标题】:nested table element assignment in pl/sqlpl/sql中的嵌套表元素赋值
【发布时间】:2014-10-27 00:37:33
【问题描述】:

我对 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) 中。 假设 indx i 的下一次迭代主 for 循环为代码生成 2 行值。我的想法是捕获异常(ORA-01422)并继续在现有的嵌套表中添加这两个代码值。

因此,实际上,我的嵌套表现在应该在其元素中包含 3 个代码值。但是,目前,我只能让它填充其中的 2 个(第一次迭代的单个值和下一次迭代的最新值)

任何关于我如何做到这一点的指针都将不胜感激。

PS:尝试操作计数器变量 indx 和 p。但是,显然 pl/sql 不允许它用于“for 循环”。

【问题讨论】:

    标签: collections plsql oracle11g


    【解决方案1】:

    您根本不需要进行一次选择,只需使用光标循环开始,然后附加到集合(您必须对其进行初始化):

    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;
    /
    

    可能有一种更快的方法来组合两个集合,但我不知道有一个。 Bulk-collect 必须是模式级别的集合类型,所以你不能使用本地的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
    

    【讨论】:

    • 感谢您的众多选择。你给出的第一个选项很简洁......不知道为什么我没有想到它......呃!
    猜你喜欢
    • 2011-10-20
    • 2018-06-17
    • 1970-01-01
    • 2020-12-09
    • 2017-03-03
    • 1970-01-01
    • 2014-08-29
    • 2013-10-25
    • 2014-04-01
    相关资源
    最近更新 更多