Oracle
 sql >> Database >  >> RDS >> Oracle

come dichiarare %ROWTYPE di una variabile che è un SYS_REFCURSOR debolmente tipizzato?

La risposta breve è che non puoi. Dovresti definire una variabile per ogni colonna che verrà restituita.

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

E poi vai nell'elenco delle colonne:

FETCH P_RS INTO L_T_COL1, L_T_COL2, ... ;

Questo è doloroso ma gestibile fintanto che sai cosa ti aspetti nel cursore di riferimento. Usando T.* nella tua procedura lo rende fragile, poiché l'aggiunta di una colonna alla tabella interromperebbe il codice che pensa di sapere quali colonne ci sono e in quale ordine si trovano. (Puoi anche interromperlo tra gli ambienti se le tabelle non sono compilate costantemente - ho visto luoghi in cui l'ordinamento delle colonne è diverso in diversi ambienti). Probabilmente vorrai comunque assicurarti di selezionare solo le colonne che ti interessano veramente, per evitare di dover definire variabili per cose che non leggerai mai.

Da 11g puoi usare il DBMS_SQL pacchetto per convertire il tuo sys_refcursor in un DBMS_SQL cursore e puoi interrogarlo per determinare le colonne. Proprio come esempio di cosa puoi fare, questo stamperà il valore di ogni colonna in ogni riga, con il nome della colonna:

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

Non è di grande utilità pratica e, per brevità, sto trattando ogni valore come una stringa poiché voglio solo stamparlo comunque. Guarda i documenti e cerca esempi per applicazioni più pratiche.

Se vuoi solo poche colonne dal tuo cursore di riferimento potresti, suppongo, girare intorno a l_desc e registra la posizione in cui column_name è ciò che ti interessa, come variabile numerica; potresti quindi fare riferimento alla colonna con quella variabile in un secondo momento dove normalmente utilizzeresti il ​​nome in un ciclo del cursore. Dipende da cosa stai facendo con i dati.

Ma a meno che tu non ti stia aspettando di non conoscere l'ordine delle colonne che stai ricevendo, il che è improbabile poiché sembri controllare la procedura e supponendo che ti sbarazzi del .* s - probabilmente è molto meglio ridurre le colonne restituite al minimo necessario e dichiararle tutte singolarmente.