Как в fetch получить один столбец из курсора, для которого нельзя указать %rowtype?

Пишу процедуру, в которой получаю курсор из другой процедуры.

Нужно с помощью fetch получить первый столбец из курсора. Так как там много столбцов, то не желательно бы заводить переменную под каждую, чтобы не было такого:

fetch into v1, v2, v3, v4, v5, v6, v7, v8

А так:

row_set  v_cursor%rowtype;

не получается сделать, потому что объявление курсора находится в другой процедуре.

bulk collect я не пробовал, но в курсоре возвращаются разные типы, а он, как я понимаю, может вернуть только в массив.


Ответы (2 шт):

Автор решения: 0xdb

Создайте пакет и поместите объявление курсора в тело пакета.

Это будет выглядеть примерно как в воиспроизводимом примере ниже:

create or replace package pack1 as
    procedure process;
end;
/
create or replace package body pack1 as
    cursor cur1 is
        select 1 col1, 2 col2, 3 col3 from dual union all
        select 4 col1, 5 col2, 6 col3 from dual;
    type currows is table of cur1%rowtype;
    procedure openCursor is
    begin 
        open cur1;
    end; 
    function fetchCursor return currows is
        ret currows; 
    begin 
        fetch cur1 bulk collect into ret;
        close cur1;
        return ret;
    end;
    procedure process is
        rs currows;
    begin 
        openCursor;
        rs := fetchCursor ();
        for i in 1..rs.count loop
            dbms_output.put_line ('col2['||i||']='||rs(i).col2); 
        end loop;
    end;
end;
/

Запуск и результат:

exec pack1.process;

col2[1]=2
col2[2]=5
→ Ссылка
Автор решения: 0xdb

Автор вопроса прокомментировал:

А как сделать, чтобы эта процедура именно возвращала курсор?

Oбъявленный в PL/SQL явный курсор нельзя вeрнуть из процедуры или функции. Вернуть можно только курсор с типом REF CURSOR. Эти типы несовместимы, т.е. нельзя переменную явного курсора присвоить переменной курсора. Но можно обрабатывать явный курсор в табличной функции, а её результат возвращать как курсор.

Посмотрите, как это сделать:

create or replace package pack2 as
    cursor cur1 is
        select 1 col1, 2 col2, 3 col3 from dual union all
        select 4 col1, 5 col2, 6 col3 from dual;
    type currows is table of cur1%rowtype;
    type refcursor is ref cursor return cur1%rowtype;
    procedure process;
    procedure opencur (rc out refcursor);  
    function getdata return currows pipelined;  
end;
/
create or replace package body pack2 as
    function getdata return currows pipelined is
    begin
        for r in cur1 loop pipe row (r); 
        end loop;
        return;
    end;
    procedure opencur (rc out refcursor) is 
    begin
        open rc for select * from table (getdata ());
    end;
    procedure process is
        rc refcursor;
        rs currows; 
    begin 
        opencur (rc);
        fetch rc bulk collect into rs;
        for i in 1..rs.count loop
            dbms_output.put_line ('col2['||i||']='||rs(i).col2); 
        end loop;
    end;
end;
/

Такое решение будет работать внутри блока и с ним можно вернуть откртый курсор:

exec pack2.process;

col2[1]=2
col2[2]=5

var rc refcursor
exec pack2.opencur (:rc);

      COL1       COL2       COL3
---------- ---------- ----------
         1          2          3
         4          5          6
→ Ссылка