Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

como declarar %ROWTYPE de uma variável que é um SYS_REFCURSOR fracamente tipado?


A resposta curta é, você não pode. Você precisaria definir uma variável para cada coluna que será retornada.
DECLARE
    P_RS SYS_REFCURSOR;
    L_T_COL1 T.COL1%TYPE;
    L_T_COL1 T.COL2%TYPE;
    ...

E, em seguida, busque na lista de colunas:
FETCH P_RS INTO L_T_COL1, L_T_COL2, ... ;

Isso é doloroso, mas gerenciável, desde que você saiba o que está esperando no cursor de referência. Usando T.* no seu procedimento torna isso frágil, pois adicionar uma coluna à tabela quebraria o código que pensa que sabe quais colunas existem e em que ordem elas estão. consistentemente - já vi lugares onde a ordenação das colunas é diferente em diferentes ambientes). Você provavelmente vai querer ter certeza de que está selecionando apenas as colunas com as quais realmente se importa, para evitar ter que definir variáveis ​​para coisas que você nunca lerá.

A partir do 11g você pode usar o DBMS_SQL pacote para converter seu sys_refcursor em um DBMS_SQL cursor, e você pode interrogá-lo para determinar as colunas. Apenas como exemplo do que você pode fazer, isso imprimirá o valor de cada coluna em cada linha, com o nome da coluna:
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;
/

Isso não é muito prático e, para resumir, estou tratando todos os valores como uma string, pois quero apenas imprimi-los de qualquer maneira. Veja os documentos e procure exemplos para aplicações mais práticas.

Se você quiser apenas algumas colunas do seu cursor ref, suponho que você possa fazer um loop em l_desc e registre a posição em que column_name é o que você estiver interessado, como uma variável numérica; você poderia então se referir à coluna por essa variável mais tarde, onde normalmente usaria o nome em um loop de cursor. Depende do que você está fazendo com os dados.

Mas a menos que você esteja esperando não saber a ordem das colunas que você está recebendo, o que é improvável, pois você parece controlar o procedimento - e supondo que você se livre do .* s - provavelmente é muito melhor reduzir as colunas retornadas ao mínimo necessário e apenas declará-las individualmente.