Skip to Main Content

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Senthil.

Asked: September 20, 2001 - 2:47 pm UTC

Last updated: September 29, 2017 - 12:25 pm UTC

Version: 8.1.5

Viewed 1000+ times

You Asked

Tom,

Here is an example...that i want to change one function to avoid redundant information.

create or replace package p_ref_cursor is
type ret_ref_cursor is ref cursor;
end p_ref_cursor;
/


drop table "tab1";

create table "tab1" (no number, city varchar2(20));

insert into "tab1" values (1, 'Boston');
insert into "tab1" values (2, 'Chicago');
insert into "tab1" values (3, 'Atlanta');


drop table "tab2";

create table "tab2" (no number, city varchar2(20));

insert into "tab2" values (1, 'London');
insert into "tab2" values (2, 'Paris');


create or replace function "fun_tab1"(p_no in number)
return p_ref_cursor.ret_ref_cursor is
l_cursor p_ref_cursor.ret_ref_cursor;
begin
open l_cursor for select * from "tab1" where no <= p_no;
return l_cursor;
end;
/


create or replace function "fun_tab2"(p_no in number)
return p_ref_cursor.ret_ref_cursor is
l_cursor p_ref_cursor.ret_ref_cursor;
begin
open l_cursor for select * from "tab2" where no <= p_no;
return l_cursor;
end;
/

create or replace function get_data(p_table_name in varchar2, p_no in number)
return p_ref_cursor.ret_ref_cursor is
l_cursor p_ref_cursor.ret_ref_cursor;
begin
if p_table_name = 'tab1' then
return "fun_tab1"(p_no);
end if;
if p_table_name = 'tab2' then
return "fun_tab2"(p_no);
end if;
end;
/


var r refcursor
exec :r := get_data('tab1', 10);
print r

exec :r := get_data('tab2', 10);
print r

and the output is...

NO CITY
---------- --------------------
1 Boston
2 Chicago
3 Atlanta


NO CITY
---------- --------------------
1 London
2 Paris




For some reasons...we used to create tables and functions as a case sensitive and also creates seperate set of independant functions and procedure for each tables. now there is a master function(get_data)... that gets table name and other values as a input parameter and calls corresponding functions. i am allowed to change the master function to remove all redundant information(if..thens...). i thought of using native dynamic sql but i couldnt. Is it possible to use native dynamic sql...if so...could you please give me the suggestions.

thanks,
senthil.

and Tom said...

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace function get_data(p_table_name in varchar2, p_no in number)
2 return p_ref_cursor.ret_ref_cursor is
3 l_cursor p_ref_cursor.ret_ref_cursor;
4 begin
5 open l_cursor for
'select * from "' || p_table_name || '" where no <= :p_no' using p_no;
6 return l_cursor;
7 end;
8 /

Function created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> variable r refcursor
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec :r := get_data('tab1', 10);
PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> print r

NO CITY
---------- --------------------
1 Boston
2 Chicago
3 Atlanta

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec :r := get_data('tab2', 10);
PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> print r

NO CITY
---------- --------------------
1 London
2 Paris

Rating

  (4 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Thanks...but,

Senthil, September 21, 2001 - 10:29 am UTC

Great answer. But i wonder is it possible to use a "Execute Immediate" in get_data function. I gave a simple query in other two functions ("fun_tab1" & "fun_tab2")...but in real time it might be having different SELECT statements...would return more than one row based on different condition. And also...the number of tables would increase and new functions will be added to it. In that case...get_data function will grow and grow further...with additional IF-THEN statements.

Tom Kyte
September 21, 2001 - 11:13 am UTC

Not with the ref cursor it isn't possible. You will get:

LINE/COL ERROR
-------- -----------------------------------------------------------------
5/2 PL/SQL: Statement ignored
5/65 PLS-00457: expressions have to be of SQL types

trying to bind a ref cursor type in dynamic SQL in PLSQL.

ref cursor with dynamic plsql table

Alok, June 11, 2004 - 11:24 am UTC

Hi sir
I'm attaching one sample code here

declare
str varchar2(32000);
str1 varchar2(32000);

a_fordnr varchar2(20);
ctr number;

TYPE REFCUR_VA IS REF CURSOR ;
va_cur REFCUR_VA;

TYPE TEMP_TAB IS TABLE OF VARCHAR2(32000) INDEX BY BINARY_INTEGER;
va_tab TEMP_TAB;
begin

va_tab(1) := 'select 1 from dual union all ';
va_tab(2) := 'select 2 from dual union all ' ;
va_tab(3) := 'select 3 from dual ' ;

open va_cur for va_tab(1)||va_tab(2)||va_tab(3);

loop
fetch va_cur into a_fordnr;
exit when va_cur%NOTFOUND;
dbms_output.put_line('Output '||a_fordnr);
end loop;
close va_cur;

exception
when others then
rollback;
dbms_output.put_line('Error '||sqlerrm);
end;


As you all noticed , that while opening the cursor i've hardcoded the all the three rows from the pl sql table.
I want a solution to add only those many rows the no of rows pl sql table is having. I can't copy in a variable and use it while opening cursor, becuase this is a sample code, actully one records size will be close to 30000 char and can't be concatenated due the limitaion of varchar2 ( 32676 ).
A help will be highly appreceaited

Alok





Tom Kyte
June 11, 2004 - 4:27 pm UTC

for i in 1 .. plsql_table_variable.count
loop
l-text := l-text || plsql-table_variable(i);
end loop;

if the sum is less than 32k -- else read about dbms_sql where you can parse an array of strings, instead of a single string.

but first -- i'd ask myself "what the HECK am i doing that would cause me to have such sql" and think (seriously) about how to do it differently.

Query

tinku, September 28, 2017 - 6:46 am UTC

What's the difference between ref cursor and native dynamic sql?

Chris Saxon
September 28, 2017 - 2:54 pm UTC

They aren't opposites: a ref cursor is a pointer to a result set.

Native dynamic SQL is typically done with execute immediate. But you can open a ref cursor using this. See:

See http://docs.oracle.com/database/122/LNPLS/dynamic-sql.htm#LNPLS01102

difference

tinku, September 29, 2017 - 6:57 am UTC

Thanks Chris. So, both ref cursor and native dynamic sql are same except only one difference.I mean ref cursor can return result set to the call.

Is that correct?
Chris Saxon
September 29, 2017 - 12:25 pm UTC

No!

You can open a ref cursor using native dynamic SQL. Or you could open it using static SQL.

And you can use NDS to do things other than open a ref cursor. Such as insert/update/delete.

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library