2017-12-22 3 views
0

カーソル上でいくつかのコードを実行したいが、カーソルの内容を報告して、プレビューはExcelのクエリテーブルで、{Call}構文の場合はREF CURSORが必要です。 PL/SQLでは、コーディングのための自然な構文は明示的なカーソルです。 this questionの@XINGの助けを借りて、私はこのパッケージを開発しました。私のスニークプレビュー用列の名前を変更せずに明示的カーソルを参照カーソルに変換するATTR_n

CREATE OR REPLACE PACKAGE MyPackage 
AS 

    -- This could be a complex query with many paramters and columns 
    CURSOR curMyCursor(pParam1 VARCHAR2) IS 
    SELECT pParam1 hello, 'ColNames' goodbye 
    FROM DUAL; 

    -- I could just let GiveMyCursor return a SYS_REFCURSOR but wanted to try max clues 
    TYPE refMyCursor IS REF CURSOR RETURN curMyCursor%ROWTYPE; 
    -- The TABLE function in GiveMyCursor needs the row type to be externalized 
    TYPE typMyCursor IS TABLE OF curMyCursor%ROWTYPE; 

    PROCEDURE RunMyCursor(pParam1 IN VARCHAR2); 
    PROCEDURE GiveMyCursor(pCursor OUT refMyCursor, pParam1 IN VARCHAR2); 

END MyPackage; 
/

CREATE OR REPLACE PACKAGE BODY MyPackage 
AS 

    PROCEDURE RunMyCursor(pParam1 IN VARCHAR2) IS 
    BEGIN 
    FOR recMyCursor IN curMyCursor(pParam1) LOOP 
     NULL; -- Do normal cursor loop processing 
    END LOOP; 
    END RunMyCursor; 

    PROCEDURE GiveMyCursor(pCursor OUT refMyCursor, pParam1 IN VARCHAR2) IS 
    tabMyCursor typMyCursor; 
    BEGIN 
    OPEN curMyCursor(pParam1); 
    -- Load the entire contents of the cursor into memory and pray it fits 
    FETCH curMyCursor BULK COLLECT INTO tabMyCursor; 
    CLOSE curMyCursor; 

    -- PROBLEM: The TABLE function renames the columns ATTR_1, ATTR_2, etc 
    OPEN pCursor FOR 
    SELECT ATTR_1 HELLO, ATTR_2 GOODBYE 
    FROM TABLE(tabMyCursor); 
    END GiveMyCursor; 

END MyPackage; 
/

私は、彼らがリフレッシュすることができソートをフィルタリングして、エンドユーザーに単純なテーブルを与えたいです。クエリを複製せずに、REF CURSORを返すプロシージャを持つ単純なExcelクエリテーブル。 {call MyPackage.GiveMyCursor('World')}が与える:

HELLO | GOODBYE 
------+--------- 
World | ColNames 

私は

を持っているでしょう OPEN pCursorの列名を再指定していなかった場合は
ATTR_1| ATTR_2 
------+--------- 
World | ColNames 

のでOPEN pCursor FOR SELECT *は私が/強化なしその他の保守と私のクエリを修正する許可されているだろうエンドユーザーは列の説明を失うことになります。

GiveMyCursorには何らかの方法がありますが、すべての列名を再指定しないようにするコードを追加できます。一部のビルトインDBMSパッケージは、カーソルやタイプの1つをインターラゲーションして文字列などを作成して汎用的に保つことができます。

私のデータベースはOracle 12.1.0.1 SEです。

+0

あなたが(例えば、[ここ]([DBMS_SQL.TO_CURSOR_NUMBER(https://docs.oracle.com/database/121/ARPLS/d_sql.htm#ARPLS68279)を使用して、REFカーソルの列を解析することができhttp://www.williamrobertson.net/documents/refcursor-to-csv.shtml))。しかし、私があなたの要件を誤解していない限り、問題はあなたが宣言したコレクションタイプの属性を知っているが、メンテナンスを簡素化するためにそれらを再度ハードコーディングすることはない。 'select * from table(tabMyCursor)'を解析するのに 'dbms_sql.to_cursor_number'を使うことができますが、実際にはカラム名が必要ですか? –

+0

@WilliamRobertson私は、なぜカラム名が必要なのか疑問に思うかもしれません。 'dbms_sql.to_cursor_number'は渡された' OPEN'ed 'REF CURSOR'を必要としますが、' SELECT * 'を持つコードがそのポイントに達すると、カラム名は失われています。 – Unoembre

答えて

2

curMyCursorそのものを渡すことができる場合は、をOUTパラメータとして使用する必要があるのはなぜか不明です。あなたのコードのコメントで

- メモリにカーソルの内容全体をロードし、それが

に合う祈るあなたはおそらくメモリ内のレコードを格納することは、より良いパフォーマンスをもたらすであろうことを想定しています?事実、CURSORを使用すると、Oracleは実際に処理情報を格納する名前のない作業領域を開きます。最初のCURSORを直接渡して呼び出しブロックで使用するのはなぜですか?

は、コレクションを宣言しながら、あなたはそれを正しく定義していない限り、あなたの場合は、声明の中で
FETCH curMyCursor BULK COLLECT INTO tabMyCursor 

は、列マッピングに列をしない、と述べました。

期待どおりの列データ型を使用してRECORDと宣言してください。

TYPE MyrecordType is RECORD 
(
hello VARCHAR2(10), 
goodbye VARCHAR2(10) 
); 
TYPE typMyCursor IS TABLE OF MyrecordType ; 

代わりの

TYPE typMyCursor IS TABLE OF curMyCursor%ROWTYPE; 

さて、あなたは、コレクション内のレコード要素のすべての列に適切な名前を持つことになります。要素を指定する代わりに、SELECT *を直接使用することができます。

OPEN pCursor FOR 
    SELECT * 
    FROM TABLE(tabMyCursor); 
+0

「最初の 'CURSOR'を直接渡す」という問題は、消費者が実際にはExcelのOracle以外にいることです。私はそれを示すために質問を変えました。 Excelに明示的なカーソルを渡すことができればと思っています。 – Unoembre

+0

それは動作します!今は 'SELECT *'を使用してカラム名を保持することができます。列名の定義は、カーソル仕様のパッケージ仕様の中に保持されます。欠点は、列名を再指定し続けなければならず、すべての列タイプも指定する必要があることです。 1つは前方に、2つは後方に。 これは私の問題の理解を進歩させます。 'OPEN pCursor'の' TABLE'機能ではなく、列名を失っていた 'TYPE refMyCursor'の' curMyCursor%ROWTYPE'でした。 – Unoembre

関連する問題