Oracle
 sql >> Database >  >> RDS >> Oracle

Oracle FOR LOOP non esegue l'iterazione in SYS_REFCURSOR

Nota dopo i commenti estesi:

Forse al centro della domanda c'è un malinteso su cosa sia un cursore. Non è un contenitore pieno di record, è una specifica per un set di risultati, come in un determinato momento, basato su una singola query SQL. Quindi se tu

open rc for select id from table1;

e passa rc al chiamante, non stai passando alcun dato, stai passando un puntatore a un'area di memoria privata contenente una query preparata. Non spingi i risultati, il chiamante li tira. È come un programma che il chiamante eseguirà per recuperare le righe. Non puoi aprirlo un po' di più per aggiungere un'altra riga, cosa che penso sia quello che speravi di fare.

Per utilizzare una raccolta in un cursore all'interno di una procedura, il tipo di raccolta deve essere creato come un oggetto schema separato (anche se ovviamente puoi riutilizzare i tipi di raccolta in altre procedure, quindi non è così restrittivo come sembra).

Se non riesci a creare un tipo, guarda quali tipi esistono già che puoi utilizzare:

select owner, type_name
from   all_coll_types t
where  t.coll_type = 'TABLE'
and    t.elem_type_name = 'NUMBER';

Ad esempio:

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;

Ora la procedura può essere:

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;

Uscita cursore:

        ID COUNT ACC
---------- ----- ---
        10 UK    PB1
        15 Wales RB
        20 SH    CC

(Ho rimosso i_id parametro nella tua procedura in quanto non ero chiaro come volevi usarlo.)

Presumibilmente questa è una versione semplificata del problema reale, perché così com'è potresti utilizzare la prima query come sottoquery e non avresti bisogno della raccolta:

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;

o semplicemente unisciti a esso, come suggerito da Littlefoot:

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;

Tuttavia, hai commentato quella risposta dicendo che non potevi farlo perché il tuo requisito sembrava essere quello di farlo tramite una raccolta, un anello, del nastro adesivo, due gatti e un generatore di fusione.