Краткият отговор е, че не можете. Ще трябва да дефинирате променлива за всяка колона, която ще бъде върната.
DECLARE
P_RS SYS_REFCURSOR;
L_T_COL1 T.COL1%TYPE;
L_T_COL1 T.COL2%TYPE;
...
И след това извлечете в списъка с колони:
FETCH P_RS INTO L_T_COL1, L_T_COL2, ... ;
Това е болезнено, но управляемо, стига да знаете какво очаквате в референтния курсор. Използване на T.*
във вашата процедура обаче прави това крехко, тъй като добавянето на колона към таблицата би разрушило кода, който смята, че знае какви колони има и в какъв ред са те. (Можете също да го разбиете между среди, ако таблиците не са изградени последователно - виждал съм места, където подреждането на колоните е различно в различни среди). Вероятно ще искате да сте сигурни, че така или иначе избирате само колоните, които наистина ви интересуват, за да избегнете необходимостта да дефинирате променливи за неща, които никога няма да прочетете.
От 11g можете да използвате DBMS_SQL
пакет, за да конвертирате вашия sys_refcursor
в DBMS_SQL
курсора и можете да го разпитате, за да определите колоните. Само като пример за това, което можете да направите, това ще отпечата стойността на всяка колона във всеки ред с името на колоната:
DECLARE
P_RS SYS_REFCURSOR;
L_COLS NUMBER;
L_DESC DBMS_SQL.DESC_TAB;
L_CURS INTEGER;
L_VARCHAR VARCHAR2(4000);
BEGIN
CAPITALEXTRACT(P_RS => P_RS);
L_CURS := DBMS_SQL.TO_CURSOR_NUMBER(P_RS);
DBMS_SQL.DESCRIBE_COLUMNS(C => L_CURS, COL_CNT => L_COLS,
DESC_T => L_DESC);
FOR i IN 1..L_COLS LOOP
DBMS_SQL.DEFINE_COLUMN(L_CURS, i, L_VARCHAR, 4000);
END LOOP;
WHILE DBMS_SQL.FETCH_ROWS(L_CURS) > 0 LOOP
FOR i IN 1..L_COLS LOOP
DBMS_SQL.COLUMN_VALUE(L_CURS, i, L_VARCHAR);
DBMS_OUTPUT.PUT_LINE('Row ' || DBMS_SQL.LAST_ROW_COUNT
|| ': ' || l_desc(i).col_name
|| ' = ' || L_VARCHAR);
END LOOP;
END LOOP;
DBMS_SQL.CLOSE_CURSOR(L_CURS);
END;
/
Това не е от голяма практическа полза и за краткост третирам всяка стойност като низ, тъй като така или иначе просто искам да го отпечатам. Разгледайте документите и потърсете примери за по-практични приложения.
Ако искате само няколко колони от вашия ref курсор, предполагам, че бихте могли да обиколите l_desc
и запишете позицията, където column_name
е всичко, което ви интересува, като числова променлива; след това можете да се обърнете към колоната с тази променлива по-късно, където обикновено ще използвате името в цикъл на курсора. Зависи какво правите с данните.
Но освен ако не очаквате да не знаете реда на колоните, който получавате обратно, което е малко вероятно, тъй като изглежда контролирате процедурата - и ако приемем, че се отървете от .*
s – вероятно е много по-добре да намалите върнатите колони до минимума, от който се нуждаете, и просто да ги декларирате поотделно.