Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fetch Oracle reference cursor into table variable?

I am trying to load data from reference cursor into a table variable (or array), the reference cursor works if the table variable is based on existingtable %Rowtype but my reference cursor gets loaded by joining multiple tables so let me try to demonstrate an example what i am trying to do and some one can help me

--created table
create table SAM_TEMP(
    col1 number null,
    col2 varchar(100) null
);

--created procedure which outputs results from that table

CREATE OR REPLACE
PROCEDURE SP_OUT_RefCur_PARAM(
    C_RESULT OUT SYS_REFCURSOR
) IS
BEGIN
    OPEN C_RESULT FOR 
        SELECT COL1,COL2
        FROM SAM_TEMP;
END SP_OUT_RefCur_PARAM;

--seeing the output works like this
DECLARE 
    REFCUR SYS_REFCURSOR;   
    outtable SAM_TEMP%rowtype ;  
BEGIN 
    SP_OUT_RefCur_PARAM(REFCUR);
    LOOP
        FETCH REFCUR INTO outtable;
        EXIT WHEN REFCUR%NOTFOUND;
        dbms_output.put_line(outtable.col1);
    END LOOP;
    CLOSE REFCUR;
END;


--but when i try to run below script it is giving error,i think i am missing something
DECLARE 
    REFCUR SYS_REFCURSOR;   
    TYPE REFTABLETYPE IS RECORD (COL1 NUMBER, COL2  VARCHAR(100));
    TYPE TABLETYPE IS TABLE OF REFTABLETYPE;
    outtable TABLETYPE; 
BEGIN 
    SP_OUT_RefCur_PARAM(REFCUR);
    LOOP
        FETCH REFCUR INTO outtable;
        EXIT WHEN REFCUR%NOTFOUND;
        dbms_output.put_line(outtable.col1);
    END LOOP;
    CLOSE REFCUR;
END;

Error report:

ORA-06550 line 9, column 21:
PLS-00597 expression 'OUTTABLE' in the INTO list is of wrong type
ORA-06550 line 9, column 3:
PL/SQL SQL Statement ignored
ORA-06550 line 11, column 32:
PLS-00302 component 'COL1' must be declared

Not sure what i am missing, Thanks in advance for your help

like image 492
sam Avatar asked Dec 06 '13 02:12

sam


People also ask

How to fetch data from REF CURSOR in Oracle?

We will examine different ways to fetch data from ref cursor. We will use SYS_REFCURSOR as ref cursor variable as its a week type of cursor. It will allow us to fetch data as per our format. First we will use simple plsql variable to fetch data from a ref cursor. --How to fetch data from ref cursor in Oracle using for loop?

How to declare a cursor variable in PL/SQL?

To declare a cursor variable, you use the REF CURSOR is the data type. PL/SQL has two forms of REF CURSOR typeS: strong typed and weak typed REF CURSOR.

Why can’t I see the data type of a REF CURSOR?

Reason: a ref cursor type in PL./SQL does not have a describe interface. So no code that you write in PL/SQL can take a ref cursor variable and dynamically determine what columns there are in the ref cursor, or what their data types are. (unless maybe with a very ugly and extremely dirty hack)

How do you use a cursor variable?

Without a cursor variable, you have to fetch all data from a cursor, store it in a variable e.g., a collection, and pass this variable as an argument. With a cursor variable, you simply pass the reference to that cursor.


2 Answers

The name of variable in code above misleaded you. Your variable outtable is in table type. It isn't possible to fetch record data into table of records, but you can fetch it into record itself.

DECLARE 
    REFCUR SYS_REFCURSOR;   
    TYPE RECORDTYPE IS RECORD (COL1 NUMBER, COL2  VARCHAR(100));
    outtable RECORDTYPE; 
BEGIN 
    SP_OUT_RefCur_PARAM(REFCUR);
    LOOP
        FETCH REFCUR INTO outtable;
        EXIT WHEN REFCUR%NOTFOUND;
        dbms_output.put_line(outtable.col1);
    END LOOP;
    CLOSE REFCUR;
END;

Update: If you want to fetch all data for better performance your application you need to use BULK COLLECT statement:

DECLARE 
    REFCUR SYS_REFCURSOR;   
    TYPE RECORDTYPE IS
        RECORD (COL1 NUMBER, COL2  VARCHAR(100));
    TYPE TABLETYPE IS
        TABLE OF REFTABLETYPE
        INDEX BY PLS_INTEGER;
    outtable TABLETYPE; 
BEGIN 
    SP_OUT_RefCur_PARAM(REFCUR);
    LOOP
        FETCH REFCUR INTO BULK COLLECT outtable;
        EXIT WHEN outtable.COUNT = 0;

        FOR indx IN 1 .. outtable.COUNT 
        LOOP
            dbms_output.put_line(outtable(indx).col1);;
        END LOOP;
    END LOOP;
    CLOSE REFCUR;
END;

Note: memory consumption with the BULK statement is much more than without.

The most important thing to remember when you learn about and start to take advantage of features such as BULK COLLECT is that there is no free lunch. There is almost always a trade-off to be made somewhere. The tradeoff with BULK COLLECT, like so many other performance-enhancing features, is "run faster but consume more memory." (Oracle Magazine)

But if you are just fetching and processing the rows - a row at a time there is no needs in BULK statement, just use the cursor FOR LOOP. (Ask Tom)

like image 61
Alexander Myshov Avatar answered Oct 26 '22 03:10

Alexander Myshov


Another way to do it is this one:

DECLARE 
    REFCUR SYS_REFCURSOR;   
    TYPE REFTABLETYPE IS RECORD (COL1 NUMBER, COL2  VARCHAR(100));
    TYPE TABLETYPE IS TABLE OF REFTABLETYPE;
    outtable TABLETYPE; 
BEGIN 
    SP_OUT_RefCur_PARAM(REFCUR);
    FETCH REFCUR BULK COLLECT INTO outtable; 
    FOR i in outtable.First..outtable.Last Loop
        dbms_output.put_line(outtable(i).col1);
    END LOOP;
    CLOSE REFCUR;
END;
like image 32
Wernfried Domscheit Avatar answered Oct 26 '22 03:10

Wernfried Domscheit