2012-06-25 7 views
8

下のW.r.tコードSYS_REFCURSORは2つのテーブルを結合するselectにあるため、基本となるテーブルの%ROWTYPEとしてfetch-into-variableの型を宣言することはできません。すなわち私はL_RECORDのT%のROWTYPE私はSYS_REFCURSORに返される列を持つ静的テーブルRを定義し、L_RECORD Rの%のROWTYPEとして宣言する必要はありません。もちろん、弱く型付けされたSYS_REFCURSORである変数の%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である変数の%ROWTYPEを宣言するにはどうすればよいですか?

答えて

14

短い答えはできません。返される列ごとに変数を定義する必要があります。

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

そして、列のリストの中にフェッチ:あなたは、REFカーソルに期待しているものを知っているよう

FETCH P_RS INTO L_T_COL1, L_T_COL2, ... ; 

これは痛みを伴うが、長いとして管理可能です。あなたの手続きでT.*を使用すると、テーブルにカラムを追加すると、そこにあるカラムとその順序を知っていると思うコードが壊れてしまうので、これは壊れやすくなります(テーブルが '一貫して構築されています - 異なる環境で列の順序が異なる場所を見てきました)。実際に気にかけている列だけを選択していることを確認して、決して読むことのない変数を定義しないようにしたいと思うでしょう。

DBMS_SQLパッケージを使用してsys_refcursorDBMS_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を取り除くと仮定 - あなたは、おそらく多くのです返される列を必要最小限に減らし、すべてを個別に宣言するほうがよいでしょう。

+0

驚くべき男、私はこれを行う方法を1年探しており、これは最高の説明だ。注:私はCAPITALEXTRACT(P_RS => P_RS)を必要としませんでした。ライン。 (実際にはエラーが発生して何が起こったのか分からなかったのでコメントアウトしてからpl/sqlが栄光に走った) – armyofda12mnkeys

+0

@ armyofda12mnkeys - 助けてくれてうれしい。 CAPITALEXTRACTはこの問題に特有の機能であり、ソリューション固有のものではありませんので、心配しないでください。 –

関連する問題