Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Wie deklariere ich %ROWTYPE einer Variablen, die ein schwach typisierter SYS_REFCURSOR ist?

Die kurze Antwort lautet:Sie können nicht. Sie müssten für jede zurückgegebene Spalte 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, ... ;

Dies ist schmerzhaft, aber überschaubar, solange Sie wissen, was Sie im Ref-Cursor erwarten. Mit T.* in Ihrer Prozedur macht dies jedoch anfällig, da das Hinzufügen einer Spalte zur Tabelle den Code beschädigen würde, der glaubt, er weiß, welche Spalten vorhanden sind und in welcher Reihenfolge sie sich befinden. (Sie können ihn auch zwischen Umgebungen unterbrechen, wenn die Tabellen nicht erstellt werden konsistent - ich habe Orte gesehen, an denen die Spaltenreihenfolge in verschiedenen Umgebungen unterschiedlich ist). Wahrscheinlich möchten Sie sicherstellen, dass Sie ohnehin nur die Spalten auswählen, die Ihnen wirklich wichtig sind, um zu vermeiden, dass Sie Variablen für Dinge definieren müssen, die Sie nie lesen werden.

Ab 11g können Sie den DBMS_SQL verwenden Paket, um Ihren sys_refcursor zu konvertieren in ein DBMS_SQL Cursor, und Sie können das abfragen, um die Spalten zu bestimmen. Nur als Beispiel dafür, was Sie tun können, wird der Wert jeder Spalte in jeder Zeile mit dem Spaltennamen ausgegeben:

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 hat keinen großen praktischen Nutzen, und der Kürze halber behandle ich jeden Wert als Zeichenfolge, da ich ihn sowieso nur drucken möchte. Sehen Sie sich die Dokumentation an und suchen Sie nach Beispielen für praktischere Anwendungen.

Wenn Sie nur ein paar Spalten von Ihrem Ref-Cursor wollen, könnten Sie, nehme ich an, eine Schleife um l_desc herum ausführen und notieren Sie die Position wo column_name ist, woran Sie interessiert sind, als numerische Variable; Sie könnten dann später über diese Variable auf die Spalte 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, Sie erwarten die Spaltenreihenfolge nicht zu kennen, die Sie zurückerhalten, was unwahrscheinlich ist, da Sie die Prozedur zu kontrollieren scheinen - und vorausgesetzt, Sie werden .* los s - Sie sind wahrscheinlich viel besser dran, wenn Sie die zurückgegebenen Spalten auf das erforderliche Minimum reduzieren und sie einfach alle einzeln deklarieren.