sql >> Databasteknik >  >> RDS >> Oracle

oracle FOR LOOP itererar inte i SYS_REFCURSOR

Observera följande utökade kommentarer:

I centrum av frågan är kanske ett missförstånd av vad en markör är. Det är inte en behållare full av poster, det är en specifikation för en resultatuppsättning, som vid en tidpunkt, baserad på en enda SQL-fråga. Så om du

open rc for select id from table1;

och skicka rc tillbaka till den som ringer, du skickar ingen data, du skickar en pekare till ett privat minnesområde som innehåller en förberedd fråga. Du pressar inte resultaten, den som ringer drar dem. Det är som ett program som den som ringer kommer att köra för att hämta raderna. Du kan inte öppna den lite mer för att lägga till ytterligare en rad, vilket jag tror är vad du hoppades på att göra.

För att använda en samling i en markör inom en procedur måste samlingstypen skapas som ett separat schemaobjekt (även om du naturligtvis kan återanvända samlingstyper i andra procedurer, så det är inte så restriktivt som det låter).

Om du inte kan skapa en typ, se vilka typer som redan finns som du kan använda:

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

Till exempel:

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;

Nu kan proceduren vara:

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;

Markörutgång:

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

(Jag tog bort i_id parametern i din procedur eftersom jag inte var tydlig med hur du ville använda den.)

Förmodligen är detta en förenklad version av det faktiska problemet, för som det ser ut kan du använda den första frågan som en underfråga och du skulle inte behöva samlingen:

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;

eller bara gå med, som Littlefoot föreslog:

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;

Men du kommenterade det svaret att du inte kunde göra det eftersom ditt krav verkade vara att göra det via en samling, en slinga, lite tejp, två katter och en fusionsgenerator.



  1. Hur frågar jag mellan två datum med MySQL?

  2. Hur visar jag det fullständiga innehållet i en text- eller varchar(MAX)-kolumn i SQL Server 2008 Management Studio?

  3. MySQL &Java - Få id för det senast infogade värdet (JDBC)

  4. Förhindra fallbord om villkoren inte är uppfyllda