Oracle
 sql >> Base de données >  >> RDS >> Oracle

oracle FOR LOOP n'itère pas dans SYS_REFCURSOR

Notez les commentaires étendus suivants :

Peut-être qu'au centre de la question se trouve un malentendu sur ce qu'est un curseur. Ce n'est pas un conteneur plein d'enregistrements, c'est une spécification pour un ensemble de résultats, comme à un moment donné, basé sur une seule requête SQL. Donc, si vous

open rc for select id from table1;

et passez rc de retour à l'appelant, vous ne transmettez aucune donnée, vous transmettez un pointeur vers une zone de mémoire privée contenant une requête préparée. Vous ne poussez pas les résultats, l'appelant les tire. C'est comme un programme que l'appelant exécutera pour récupérer les lignes. Vous ne pouvez pas l'ouvrir un peu plus pour ajouter une autre ligne, ce que je pense être ce que vous espériez faire.

Pour utiliser une collection dans un curseur au sein d'une procédure, le type de collection doit être créé en tant qu'objet de schéma séparé (bien que vous puissiez bien sûr réutiliser les types de collection dans d'autres procédures, ce n'est donc pas aussi restrictif que cela puisse paraître).

Si vous ne pouvez pas créer de type, voyez quels types existent déjà et que vous pouvez utiliser :

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

Par exemple :

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;

Maintenant la procédure peut être :

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;

Sortie curseur :

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

(J'ai supprimé le i_id paramètre dans votre procédure car je n'étais pas clair comment vous vouliez l'utiliser.)

Il s'agit probablement d'une version simplifiée du problème réel, car dans l'état actuel des choses, vous pourriez utiliser la première requête comme sous-requête et vous n'auriez pas besoin de la collection :

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 rejoignez-le simplement, comme Littlefoot l'a suggéré :

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;

Cependant, vous avez commenté cette réponse que vous ne pouviez pas le faire parce que votre exigence semblait être de le faire via une collection, une boucle, du ruban adhésif, deux chats et un générateur de fusion.