Oracle
 sql >> Base de données >  >> RDS >> Oracle

comment déclarer %ROWTYPE d'une variable qui est un SYS_REFCURSOR faiblement typé ?

La réponse courte est, vous ne pouvez pas. Vous devez définir une variable pour chaque colonne qui sera renvoyée.

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

Puis récupérez dans la liste des colonnes :

FETCH P_RS INTO L_T_COL1, L_T_COL2, ... ;

C'est douloureux mais gérable tant que vous savez ce que vous attendez dans le curseur de référence. Utilisation de T.* dans votre procédure rend cela fragile, car l'ajout d'une colonne à la table casserait le code qui pense savoir quelles colonnes il y a et dans quel ordre elles se trouvent. (Vous pouvez également le casser entre les environnements si les tables ne sont pas construites systématiquement - j'ai vu des endroits où l'ordre des colonnes est différent dans différents environnements). De toute façon, vous voudrez probablement vous assurer que vous ne sélectionnez que les colonnes qui vous intéressent vraiment, pour éviter d'avoir à définir des variables pour des choses que vous ne lirez jamais.

A partir de 11g vous pouvez utiliser le DBMS_SQL package pour convertir votre sys_refcursor dans un DBMS_SQL curseur, et vous pouvez l'interroger pour déterminer les colonnes. Juste comme exemple de ce que vous pouvez faire, cela imprimera la valeur de chaque colonne dans chaque ligne, avec le nom de la colonne :

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

Ce n'est pas d'une grande utilité pratique, et par souci de brièveté, je traite chaque valeur comme une chaîne puisque je veux juste l'imprimer de toute façon. Consultez la documentation et recherchez des exemples d'applications plus pratiques.

Si vous ne voulez que quelques colonnes de votre curseur de référence, vous pouvez, je suppose, faire une boucle autour de l_desc et enregistrez la position où column_name est tout ce qui vous intéresse, en tant que variable numérique ; vous pouvez ensuite faire référence à la colonne par cette variable plus tard où vous utiliseriez normalement le nom dans une boucle de curseur. Cela dépend de ce que vous faites avec les données.

Mais à moins que vous attendiez de ne pas connaître l'ordre des colonnes que vous récupérez, ce qui est peu probable puisque vous semblez contrôler la procédure - et en supposant que vous vous débarrassez du .* s - vous feriez probablement mieux de réduire les colonnes renvoyées au minimum dont vous avez besoin et de les déclarer toutes individuellement.