Oracle-выбор определенного столбца из курсора ref

У меня есть таблица с именем table1. Он имеет много столбцов, один из них Column1. Я не знаю других колонок, они могут даже иногда меняться. Существует строго типизированный тип курсора ref, который возвращает Table1%rowtype с именем cur_Table1. У меня есть хранимая процедура с именем SP1, которая имеет параметр out типа cur_Table1. Я вызываю эту хранимую процедуру SP1 из другой базы данных, которая видит только эту хранимую процедуру, но не таблицу или сам тип. Как выбрать только Column1 из возвращенный курсор? Я знаю, что могу получить запись или столько переменных, сколько столбцов имеет курсор, но я знаю только о существовании одного столбца, поэтому я не могу объявить полную запись или правильное количество переменных.

3 ответов


вы можете сделать это с помощью DBMS_SQL, но это не совсем.

таблица и примеры данных (столбец 1 имеет номера 1-10):

create table table1(column1 number, column2 date, column3 varchar2(1000), column4 clob);

insert into table1
select level, sysdate, level, level from dual connect by level <= 10;
commit;

пакет с процедурой, которая открывает курсор ref и выбирает все:

create or replace package test_pkg is
    type cur_Table1 is ref cursor return table1%rowtype;
    procedure sp1(p_cursor in out cur_table1);
end;
/

create or replace package body test_pkg is
    procedure sp1(p_cursor in out cur_table1) is
    begin
        open p_cursor for select column1, column2, column3, column4 from table1;
    end;
end;
/

блок PL/SQL, который считывает данные COLUMN1 из курсора ref:

--Basic steps are: call procedure, convert cursor, describe and find columns,
--then fetch rows and retrieve column values.
--
--Each possible data type for COLUMN1 needs to be added here.
--Currently only NUMBER is supported.
declare
    v_cursor sys_refcursor;
    v_cursor_number number;

    v_columns number;
    v_desc_tab dbms_sql.desc_tab;
    v_position number;
    v_typecode number;
    v_number_value number;
begin
    --Call procedure to open cursor
    test_pkg.sp1(v_cursor);
    --Convert cursor to DBMS_SQL cursor
    v_cursor_number := dbms_sql.to_cursor_number(rc => v_cursor);
    --Get information on the columns
    dbms_sql.describe_columns(v_cursor_number, v_columns, v_desc_tab);

    --Loop through all the columns, find COLUMN1 position and type
    for i in 1 .. v_desc_tab.count loop
        if v_desc_tab(i).col_name = 'COLUMN1' then
            v_position := i;
            v_typecode := v_desc_tab(i).col_type;

            --Pick COLUMN1 to be selected.
            if v_typecode = dbms_types.typecode_number then
                dbms_sql.define_column(v_cursor_number, i, v_number_value);
            --...repeat for every possible type.
            end if;
        end if;
    end loop;

    --Fetch all the rows, then get the relevant column value and print it
    while dbms_sql.fetch_rows(v_cursor_number) > 0 loop
        if v_typecode = dbms_types.typecode_number then
            dbms_sql.column_value(v_cursor_number, v_position, v_number_value);
            dbms_output.put_line('Value: '||v_number_value);
        --...repeat for every possible type
        end if;
    end loop;   
end;
/

учитывая первоначальный вопрос, ответ джонарла по-прежнему верен, поэтому я оставлю его отмеченным как таковой, но я закончил делать что-то совершенно другое и намного лучше.

проблема заключалась в том, что у меня нет контроля над базой данных SP1, мне просто нужно позвонить из другого места в качестве стороннего клиента. Теперь мне удалось получить разрешение видеть не только SP, но и тип курсора. Я все еще не вижу таблицу, но теперь есть гораздо более чистое решение:

In другой базы данных у меня есть доступ к такого типа:

type cur_Table1 is ref cursor return Table1%rowtype;

поэтому в моей базе данных я могу сделать это так:

mycursor OtherDB.cur_Table1;
myrecord mycursor%rowtype;
...
OtherDB.SP1(mycursor);
fetch mycursor into myrecord;
dbms_output.put_line(myrecord.Column1);

видите, мне все еще не нужен доступ к таблице,я вижу только курсор. Ключ в том, что волшебный %rowtype работает и для курсоров, а не только для таблиц. Он не работает на sys_refcursor, но он работает на строго типизированном. Учитывая этот код, мне не нужно беспокоиться, если что-то изменится на другой стороне, мне не нужно определять все столбцы или записи вообще, я просто указываю один столбец, который меня интересует.

мне очень нравится это отношение ООП к Oracle.


Не знаю, является ли это вариантом или нет, но не было бы лучшим решением создать функцию, которая возвращает конкретное значение, которое вы ищете? Это позволяет избежать накладных расходов на отправку дополнительных данных. Кроме того, вы можете определить курсор с набором известных полей, о которых знают обе стороны.