2012-06-25 3 views
8

W.r.t-Code unten Ich kann den Typ von fetch-in-Variable nicht als den% ROWTYPE der zugrundeliegenden Tabelle deklarieren, da sich SYS_REFCURSOR auf einer Auswahl befindet, die zwei Tabellen verbindet und auch einige Funktionen für die Attribute der zugrunde liegenden zwei Tabellen auswählt; das heißt ich kann nicht erklären, wie L_RECORD T% ROWTYPEwie% ROWTYPE einer Variablen, die ein schwach typisiertes SYS_REFCURSOR ist, zu deklarieren?

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

Natürlich möchte ich nicht eine statische Tabelle R mit Spalten definieren, wie in der sys_refcursor zurückgegeben und dann als L_RECORD R% ROWTYPE zu erklären.

Und daher die Frage: wie% ROWTYPE einer Variablen, die eine schwach typisierte SYS_REFCURSOR ist zu deklarieren?

Antwort

14

Die kurze Antwort ist, können Sie nicht. Sie müssten für jede Spalte, die zurückgegeben werden soll, eine Variable definieren.

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

Und dann in die Liste der Spalten holen:

FETCH P_RS INTO L_T_COL1, L_T_COL2, ... ; 

Das ist schmerzhaft, aber tragbar, solange Sie wissen, was Sie in der ref Cursor erwartest. Die Verwendung von T.* in Ihrer Prozedur macht dies jedoch fragil, da das Hinzufügen einer Spalte zur Tabelle den Code unterbricht, der denkt, dass er weiß, welche Spalten es gibt und in welcher Reihenfolge sie sich befinden. (Sie können sie auch zwischen Umgebungen trennen, wenn die Tabellen nicht t konsistent gebaut - ich habe Orte gesehen, an denen die Reihenfolge der Spalten in verschiedenen Umgebungen unterschiedlich ist. Sie werden wahrscheinlich sicherstellen wollen, dass Sie nur die Spalten auswählen, die Ihnen wirklich wichtig sind, damit Sie keine Variablen für Dinge definieren müssen, die Sie nie lesen werden.

Von 11g können Sie das DBMS_SQL Paket verwenden, um Ihre sys_refcursor in einen DBMS_SQL Cursor zu konvertieren, und Sie können das abfragen, um die Spalten zu ermitteln. Nur als Beispiel dafür, was man tun kann, wird dies den Wert jeder Spalte in jeder Zeile, mit dem Spaltennamen ausdrucken:

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

Das ist nicht viel praktische Gebrauch ist, und die Kürze halb Ich behandle jede Wert als String, da ich es sowieso nur ausdrucken möchte. Sehen Sie sich die Dokumentation an und suchen Sie nach Beispielen für praktische Anwendungen.

Wenn Sie nur ein paar Spalten von Ihrem Ref-Cursor möchten, könnten Sie, wie ich vermute, eine Schleife um l_desc machen und die Position, an der column_name interessiert ist, als numerische Variable aufzeichnen; Sie könnten später auf die Spalte durch diese Variable verweisen, wo Sie normalerweise den Namen in einer Cursorschleife verwenden würden. Hängt davon ab, was Sie mit den Daten machen.

Aber es sei denn, du bist erwartet nicht die Spalte, um zu wissen, Sie bekommen zurück, die seit Sie unwahrscheinlich ist, scheint das Verfahren zu steuern - und vorausgesetzt, Sie der .* s los - Sie sind wahrscheinlich viel besser, reduzieren Sie die zurückgegebenen Spalten auf das Minimum, das Sie brauchen, und deklarieren Sie alle einzeln.

+0

Ehrfürchtiger Mann, ich habe nach einem Jahr gesucht, wie man das macht und das erklärte es am besten. Hinweis: Ich brauchte den CAPITALEXTRACT nicht (P_RS => P_RS); Linie. (In der Tat war es fehlerhaft, war nicht sicher, was es getan hat, so dass ich auskommentiert und meine pl/SQL lief dann glorreich) – armyofda12mnkeys

+0

@ armeeofda12mnkeys - froh, dass es geholfen hat. CAPITALEXTRACT war eine für diese Frage spezifische Funktion, nicht etwas, das der Lösung innewohnt, also machen Sie sich deswegen keine Sorgen. –

Verwandte Themen