2012-06-25 12 views
8

Kod w .r.t poniżej Nie mogę zadeklarować typu parametru Fetch-to-zmienna jako tabela% ROWTYPE tabeli bazowej, ponieważ SYS_REFCURSOR jest na selekcji, która łączy dwie tabele, a także wybiera kilka funkcji wywoływanych na atrybutach dwóch podstawowych tabel; tzn nie mogę zadeklarować jako L_RECORD T% ROWTYPEjak zadeklarować% ROWTYPE zmiennej, która jest słabo wpisanym SYS_REFCURSOR?

--- 
DECLARE 
    P_RS SYS_REFCURSOR; 
    L_RECORD P_RS%ROWTYPE; 
BEGIN 
    CAPITALEXTRACT(
    P_RS => P_RS 
); 
    OPEN P_RS; 
    LOOP 
     BEGIN 
     FETCH P_RS INTO L_RECORD; 
     EXIT WHEN P_RS%NOTFOUND; 
     ... 
     EXCEPTION 
     WHEN OTHERS THEN 
     ... 
     END; 
    END LOOP; 
    CLOSE P_RS; 
END; 
-------- 
CREATE or REPLACE PROCEDURE CAPITALEXTRACT 
(
    p_rs OUT SYS_REFCURSOR 
) AS 
BEGIN 
    OPEN p_rs for 
    select t.*,tminusone.*, f(t.cash), g(t.cash) FROM T t, TMINUSONE tminusone 
    where t.ticket=tminusone.ticket; 
END CAPITALEXTRACT; 

Oczywiście nie chcę, aby zdefiniować statyczną tablicę R z kolumnami jak zwracane w SYS_REFCURSOR a następnie zadeklarować jako L_RECORD R% ROWTYPE.

A zatem pytanie: jak zadeklarować% ROWTYPE zmiennej, która jest słabo wpisanym SYS_REFCURSOR?

Odpowiedz

14

Krótka odpowiedź brzmi: nie możesz. Będziesz musiał zdefiniować zmienną dla każdej kolumny, która zostanie zwrócona.

DECLARE 
    P_RS SYS_REFCURSOR; 
    L_T_COL1 T.COL1%TYPE; 
    L_T_COL1 T.COL2%TYPE; 
    ... 

A potem sprowadzić do listy kolumn:

FETCH P_RS INTO L_T_COL1, L_T_COL2, ... ; 

Jest to bolesne, ale do opanowania tak długo, jak wiesz co czekasz w ref kursora. Używanie w procedurze T.* powoduje, że jest to delikatne, ponieważ dodanie kolumny do tabeli spowodowałoby złamanie kodu, który wydaje się, że wie, jakie kolumny istnieją i w jakiej kolejności się znajdują. (Możesz również podzielić go między środowiska, jeśli tabele nie są ustawione) t budowane konsekwentnie - widziałem miejsca, w których kolejność kolumn jest różna w różnych środowiskach). Prawdopodobnie będziesz chciał upewnić się, że wybierasz tylko te kolumny, na których tak naprawdę zależy, aby uniknąć konieczności definiowania zmiennych dla rzeczy, których nigdy nie przeczytasz.

Od 11g można użyć pakietu DBMS_SQL, aby przekonwertować swój sys_refcursor na kursor DBMS_SQL i można go przesłuchać w celu ustalenia kolumn. Tylko jako przykład tego, co można zrobić, to wydrukować wartość każdej kolumnie w każdym wierszu z nazwą kolumny:

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

to nie jest znacznie praktyczne zastosowanie, a dla zwięzłości ja traktując każdy wartość jako ciąg znaków, ponieważ po prostu chcę go wydrukować. Przejrzyj dokumenty i wyszukaj przykłady dla bardziej praktycznych zastosowań.

Jeśli potrzebujesz tylko kilku kolumn z kursora ref, możesz, jak przypuszczam, wykonać pętlę około l_desc i zapisać pozycję, w której column_name jest tym, co cię interesuje, jako zmienną numeryczną; możesz później odnieść się do kolumny przez tę zmienną, w której normalnie używałbyś tej nazwy w pętli kursora. Zależy od tego, co robisz z danymi.

Ale jeśli nie jesteś spodziewa nie wiedzieć kolejność kolumn dostajesz z powrotem, co jest mało prawdopodobne, ponieważ wydają się kontrolować procedurę - i zakładając, że pozbyć się .* s - jesteś prawdopodobnie znacznie lepiej zmniejszyć zwracane kolumny do minimum i po prostu zadeklarować je wszystkie indywidualnie.

+0

Awesome man, szukałem roku, jak to zrobić i to wyjaśniło to najlepiej. Uwaga: Nie potrzebowałem CAPITALEXTRACT (P_RS => P_RS); linia. (w rzeczywistości to się zepsuło, nie byłem pewien, co zrobił, więc skomentowałem i mój pl/sql następnie działał wspaniale) – armyofda12mnkeys

+0

@ armyofda12mnkeys - cieszę się, że pomogło. CAPITALEXTRACT był funkcją specyficzną dla tego pytania, a nie czymś nieodłącznym dla rozwiązania, więc nie martw się o to. –

Powiązane problemy