sql >> Base de Datos >  >> RDS >> Oracle

¿Cómo declarar %ROWTYPE de una variable que es un SYS_REFCURSOR débilmente tipado?

La respuesta corta es que no puedes. Deberá definir una variable para cada columna que se devolverá.

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

Y luego busca en la lista de columnas:

FETCH P_RS INTO L_T_COL1, L_T_COL2, ... ;

Esto es doloroso pero manejable siempre que sepa lo que espera en el cursor de referencia. Usando T.* Sin embargo, en su procedimiento hace que esto sea frágil, ya que agregar una columna a la tabla rompería el código que cree que sabe qué columnas hay y en qué orden están. (También puede dividirlo entre entornos si las tablas no están construidas consistentemente:he visto lugares donde el orden de las columnas es diferente en diferentes entornos). Probablemente querrá asegurarse de que solo selecciona las columnas que realmente le interesan de todos modos, para evitar tener que definir variables para cosas que nunca leerá.

Desde 11g puedes usar el DBMS_SQL paquete para convertir su sys_refcursor en un DBMS_SQL cursor, y puede interrogarlo para determinar las columnas. Solo como un ejemplo de lo que puede hacer, esto imprimirá el valor de cada columna en cada fila, con el nombre de columna:

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

Eso no tiene mucho uso práctico y, por brevedad, estoy tratando cada valor como una cadena, ya que solo quiero imprimirlo de todos modos. Mire los documentos y busque ejemplos para aplicaciones más prácticas.

Si solo desea unas pocas columnas de su cursor de referencia, supongo que podría recorrer l_desc y registre la posición donde column_name es lo que le interese, como una variable numérica; luego podría referirse a la columna por esa variable más tarde donde normalmente usaría el nombre en un bucle de cursor. Depende de lo que esté haciendo con los datos.

Pero a menos que estés esperando para no saber el orden de las columnas que está recibiendo, lo cual es poco probable ya que parece controlar el procedimiento, y suponiendo que se deshaga del .* s - probablemente sea mucho mejor si reduce las columnas devueltas al mínimo que necesita y simplemente las declara todas individualmente.