Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

oracle FOR LOOP não itera em SYS_REFCURSOR


Observe os seguintes comentários estendidos:

Talvez no centro da questão esteja um mal-entendido sobre o que é um cursor. Não é um container cheio de registros, é uma especificação para um conjunto de resultados, como em um momento, baseado em uma única consulta SQL. Então, se você
open rc for select id from table1;

e passe rc de volta para o chamador, você não está passando nenhum dado, você está passando um ponteiro para uma área de memória privada contendo uma consulta preparada. Você não empurra os resultados, o chamador os puxa. É como um programa que o chamador executará para buscar as linhas. Você não pode abri-lo um pouco mais para adicionar outra linha, o que acho que é o que você esperava fazer.

Para usar uma coleção em um cursor dentro de um procedimento, o tipo de coleção deve ser criado como um objeto de esquema separado (embora, é claro, você possa reutilizar tipos de coleção em outros procedimentos, portanto, não é tão restritivo quanto parece).

Se você não puder criar um tipo, veja quais tipos já existem que você pode usar:
select owner, type_name
from   all_coll_types t
where  t.coll_type = 'TABLE'
and    t.elem_type_name = 'NUMBER';

Por exemplo:
create or replace type number_tt as table of number;

create table table1 (id primary key, currency, t_id) as
    select 10, 'GBP', 'PB1' from dual union all
    select 15, 'GBP', 'RB' from dual union all
    select 20, 'GBP', 'CC' from dual union all
    select 25, 'AUD', 'DC' from dual;

create table table2 (id,country,account) as
    select 10, 'UK', 'PB1' from dual union all
    select 15, 'Wales', 'RB' from dual union all
    select 20, 'SH', 'CC' from dual;

Agora o procedimento pode ser:
create or replace procedure myproc
    ( rc out sys_refcursor)
as
    l_names number_tt;
begin
    select id bulk collect into l_names
    from   table1
    where  currency = 'GBP';

    open rc for
        select t.id,t.country,t.account from table2 t
        where  t.id member of l_names;
end myproc;

Saída do cursor:
        ID COUNT ACC
---------- ----- ---
        10 UK    PB1
        15 Wales RB
        20 SH    CC

(Removi o i_id parâmetro em seu procedimento, pois não estava claro como você queria usá-lo.)

Presumivelmente, esta é uma versão simplificada do problema real, porque, como está, você poderia usar a primeira consulta como uma subconsulta e não precisaria da coleção:
create or replace procedure myproc
    ( rc out sys_refcursor)
as
begin
    open rc for
        select t.id,t.country,t.account from table2 t
        where  t.id in
               ( select id 
                 from   table1
                 where  currency = 'GBP' );
end myproc;

ou apenas junte-se a ele, como Littlefoot sugeriu:
create or replace procedure myproc
    ( rc out sys_refcursor)
as
begin
    open rc for
        select t2.id, t2.country, t2.account
        from   table1 t1
               join table2 t2 on t2.id = t1.id
        where  t1.currency = 'GBP';
end myproc;

No entanto, você comentou nessa resposta que não poderia fazer isso porque sua exigência parecia ser fazê-lo por meio de uma coleção, um loop, um pouco de fita adesiva, dois gatos e um gerador de fusão.