8

以下の WRT コードでは、SYS_REFCURSOR が 2 つのテーブルを結合し、基になる 2 つのテーブルの属性に対して呼び出されるいくつかの関数を選択する選択にあるため、fetch-into-variable の型を基になるテーブルの %ROWTYPE として宣言できません。つまり、L_RECORD T%ROWTYPE として宣言できません。

---
DECLARE
  P_RS SYS_REFCURSOR;
  L_RECORD P_RS%ROWTYPE;
BEGIN
  CAPITALEXTRACT(
    P_RS => P_RS
  );
    OPEN P_RS;
    LOOP
      BEGIN
        FETCH P_RS INTO L_RECORD;
        EXIT WHEN P_RS%NOTFOUND;
        ...
      EXCEPTION
        WHEN OTHERS THEN
        ...
      END;
    END LOOP;
    CLOSE P_RS;
END;
--------
CREATE or REPLACE PROCEDURE CAPITALEXTRACT
(
    p_rs OUT SYS_REFCURSOR
) AS
BEGIN
  OPEN p_rs for 
     select t.*,tminusone.*, f(t.cash), g(t.cash) FROM T t, TMINUSONE tminusone
    where t.ticket=tminusone.ticket;
END CAPITALEXTRACT;

もちろん、SYS_REFCURSOR で返された列を含む静的テーブル R を定義してから、L_RECORD R%ROWTYPE として宣言したくはありません。

したがって、質問: 弱く型付けされた SYS_REFCURSOR である変数の %ROWTYPE を宣言する方法は?

4

1 に答える 1

14

簡単に言えば、できません。返される列ごとに変数を定義する必要があります。

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

次に、列のリストにフェッチします。

FETCH P_RS INTO L_T_COL1, L_T_COL2, ... ;

これは面倒ですが、ref カーソルに何が期待されているかを知っている限り、扱いやすいものです。ただし、テーブルに列を追加すると、どの列があり、どのような順序であるかを知っていると考えるコードが壊れてしまうため、手順で使用T.*するとこれが壊れやすくなります。一貫して構築されています - 環境によって列の順序が異なる場所を見てきました)。絶対に読まないものに対して変数を定義する必要がないように、とにかく本当に関心のある列だけを選択していることを確認したいでしょう。

11gから、DBMS_SQLパッケージを使用sys_refcursorしてDBMS_SQLカーソルをカーソルに変換し、それを調べて列を決定できます。できることの例として、これはすべての行のすべての列の値を列名とともに出力します。

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

それはあまり実用的ではありません。簡潔にするために、すべての値を文字列として扱います。とにかくそれを印刷したいからです。ドキュメントを見て、より実用的なアプリケーションの例を検索してください。

参照カーソルから数列だけが必要な場合は、ループして、関心のある位置を数値変数としてl_desc記録することができると思います。column_nameその後、通常はカーソル ループで名前を使用する場所で、その変数によって列を参照できます。データで何をしているかによって異なります。

ただし、返される列の順序がわからないことを期待していない限り、手順を制御しているように見えるため、これはほとんどありません。また、s を取り除くと仮定すると.*、返される列を必要最小限のものをすべて個別に宣言するだけです。

于 2012-06-27T19:54:37.170 に答える