2012-04-25 3 views
8

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

+0

Просьба пояснить, как вы предлагаете вызывать процедуру в другой базе данных (или любой другой базе данных, если на то пошло), не имея возможности видеть типы аргументов. –

+0

Я выполнил «предоставление выполнения на SP другому», но не предоставил ничего другого, кроме таблицы или типа. И это работает. – fejesjoco

+0

О, и на вызывающей стороне я, конечно, поместил параметр out из SP в sys_refcursor. – fejesjoco

ответ

6

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

Таблица и примеры данных (COLUMN1 имеет число 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; 

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

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; 
/
+7

Вау ... и я подумал, что это будет нечто тривиальное, как «select column1 from cursor». – fejesjoco

1

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

+0

У меня нет контроля над базой данных SP, мне просто нужно позвонить ему из другого места в качестве стороннего клиента. – fejesjoco

3

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

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

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

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.

Смежные вопросы