Ref Cursor Using Dynamic Query
Hi,
I need to use the ref cursor to fetch result from dynamic query.
e.g.
Open ref_test_tbl for Select * from tbl1 where tbl1.field1= :1
and tbl1.field2 =:2 using i_v1,i_v2;
The thing is i_v1, i_v2 are dynamic.
i.e. using clause can include i_v3, i_v4 also.
How to include dynamic variables in the using clause.
thanks
> How to include dynamic variables in the using clause.
Cannot using a ref cursor.. (and anyone that post code that writes dynamic PL/SQL in order to achieve this, I will call an idiot).
What you should be using in PL/SQL is a DBMS_SQL cursor. This allows you to create a fully dynamic SQL statement with bind variables. E.g.
select * from tbl1 where col1 = :1
select * from tbl1 where col2 = :1 order by 2
select * from tbl1 where col3 between :0 and :1
Using this dynamically created SQL statement, you can parse it using DBMS_SQL, determine the number of bind variables, and bind each of these dynamically.
You can then execute the SQL and again, dynamically, determine just what the projection of the cursor is. How many columns are returned, their names, data types, precision and so on.
This is what APEX (see http://apex.oracle.com) use extensively in order to run SQLs and render these as reports - all dynamically.
DBMS_SQL is detailed in the [url http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_sql.htm#BABEDAHF]Oracle® Database PL/SQL Packages and Types Reference manual.
Similar Messages
-
Create cursor using dynamic query
Hi,
I declare a query:
l_query VARCHAR2(32000):= 'select distinct '||:P_ITEM||' from OCM_CUSTOMER';
How can i assign this query to cursor?
I tried this, but failed.
Declare
l_query VARCHAR2(32000):= 'select distinct '||:P_ITEM||' from OCM_CUSTOMER';
CURSOR l_cur IS l_query;
Begin
End
thanks for help on this.Hello,
You need to use a REF CURSOR for that (there are some examples in the Oracle docs). Here is a code example:
DECLARE
TYPE EmpCurTyp IS REF CURSOR;
emp_cv EmpCurTyp;
emp_rec emp%ROWTYPE;
sql_stmt VARCHAR2(200);
my_job VARCHAR2(15) := 'CLERK';
BEGIN
sql_stmt := 'SELECT * FROM emp WHERE job = :j';
OPEN emp_cv FOR sql_stmt USING my_job;
LOOP
FETCH emp_cv INTO emp_rec;
EXIT WHEN emp_cv%NOTFOUND;
-- process record
END LOOP;
CLOSE emp_cv;
END;Greetings,
Roel
http://roelhartman.blogspot.com/ -
Help! Inaccessible iterator when using dynamic query
Hi!
I have a problem retreiving results from a dynamic query into sqlj iterator.
I consulted the Oracle App Dev Guide and Oracle SQLJ Dev Guide and wrote the following code:
<PRE>
package pmServer;
#sql iterator LocIterator (int id, String name);
public class pmRISDImpl
public int GetLocations(...)
LocIterator locIt;
String q = "select ID, NAME from PMADM.LOCATIONS";
#sql
BEGIN
open :OUT locIt for :q;
END;
</PRE>
When I try to compile it using tools provided by JDeveloper ver 3.2.2.(Build 915) for JDK 1.2.2 I get error for #sql statement:
Inaccessible Java type for host item locIt (at position #1): pmServer.LocIterator
and warning:
Type pmServer.LocIterator of host item locIt (at position #1) is not permitted in JDBC. This will not be portable.
Althow the code is identcal to those demonstrated in Oracle document "Oracle8 i
SQLJ Developers Guide and Reference
Release 3 (8.1.7)
July 2000
Part No. A83723-01" pp 12-67 (PL/SQL in SQLJ for Dynamic SQLDynamicDemo.sqlj). There it looks like
<PRE>
private static void dynamicSelectMany(String what_cond)
throws SQLException {
System.out.println("dynamic multi-row query on table emp");
Employees empIter;
// table/column names cannot be bind args in dynamic PL/SQL, so
// build up query as Java string
String query = "select ename, sal from emp " +
(((what_cond == null) | | (what_cond.equals(""))) ? "" :
(" where " + what_cond)) +
"order by ename";
#sql {
begin
open :OUT empIter for -- opening ref cursor with dynamic query
:query;
-- can have USING clause here if needed
end;
while (empIter.next()) {
System.out.println("Employee " + empIter.ename() +
" has salary " + empIter.sal() );
empIter.close();
</PRE>
Please guide me what should I do to get it working.
nullIn the CAST statement the SQLJ runtime must be able to produce an instance of you SQLJ iterator using Java reflection.
This necessitates that the iterator class must be accessible by public.
You have two options:
(1) Declare the iterator public. This requires that you put it in its own file LocIterator.sqlj:
#sql public iterator LocIterator (int id, String name);
(2) Declare the iterator as an inner class. In this case you want to make it public static (that is it does not require an instance of the outer class in scope). You might write the following.
package pmServer;
public class pmRISDImpl
#sql public static iterator LocIterator (int id, String name);
(3) If you are using Oracle 9i you have another option. You can embed dynamic SQL fragments directly in your SQLJ code and do not need to use the CAST:
public int GetLocations(...)
LocIterator locIt;
String q = "PMADM.LOCATIONS";
#sql locIt = { select ID, NAME from :{q} }; // Note new syntax :{q} for embedding SQL source code
} -
Report using ref cursor or dynamic Sql
Hi,
I never create a report using a ref cursor or a dynamic sql. Could any one help me to solve the below issue.
I have 2 tables.
1. Student_Record
2. Student_csv_help
Student_Record the main table where the data is stored.
Student_csv_help will contain the all the column names of the Student_record.
CREATE TABLE Student_CSV_HELP
ENTRY_ID NUMBER,
RAW_NAME VARCHAR2(40 BYTE),
DESC_NAME VARCHAR2(1000 BYTE),
IN_OUTPUT_LIST VARCHAR2(1 BYTE)
SET DEFINE OFF;
Insert into TOA_CSV_HELP
(ENTRY_ID, RAW_NAME, DESC_NAME, IN_OUTPUT_LIST)
Values
(1, 'S_ID', 'Student ID', 'Y');
Insert into TOA_CSV_HELP
(ENTRY_ID, RAW_NAME, DESC_NAME, IN_OUTPUT_LIST)
Values
(2, 'S_Name', 'Student Name', 'Y');
Insert into TOA_CSV_HELP
(ENTRY_ID, RAW_NAME, DESC_NAME, IN_OUTPUT_LIST)
Values
(3, 'S_Join_date', 'Joining Date', 'Y');
Insert into TOA_CSV_HELP
(ENTRY_ID, RAW_NAME, DESC_NAME, IN_OUTPUT_LIST)
Values
(4, 'S_Address', 'Address', 'Y');
Insert into TOA_CSV_HELP
(ENTRY_ID, RAW_NAME, DESC_NAME, IN_OUTPUT_LIST)
Values
(5, 'S_Fee', 'Tution Fee', 'N');
commit;
CREATE TABLE Student_record
S_ID NUMBER,
S_Name VARCHAR2(100 BYTE),
S_Join_date date,
S_Address VARCHAR2(360 BYTE),
S_Fee Number
Insert into Student_record
(S_ID, S_Name, S_Join_date, S_Address,S_Fee)
Values
(101, 'john', TO_DATE('12/17/2009 08:00:00', 'MM/DD/YYYY HH24:MI:SS'), 'CA-94777', 2000);
Insert into Student_record
(S_ID, S_Name, S_Join_date, S_Address,S_Fee)
Values
(102, 'arif', TO_DATE('12/18/2009 08:00:00', 'MM/DD/YYYY HH24:MI:SS'), 'CA-94444', 3000);
Insert into Student_record
(S_ID, S_Name, S_Join_date, S_Address,S_Fee)
Values
(103, 'raj', TO_DATE('12/19/2009 08:00:00', 'MM/DD/YYYY HH24:MI:SS'), 'CA-94555', 2500);
Insert into Student_record
(S_ID, S_Name, S_Join_date, S_Address,S_Fee)
Values
(104, 'singh', TO_DATE('12/20/2009 08:00:00', 'MM/DD/YYYY HH24:MI:SS'), 'CA-94666', 2000);
Commit;
Now my requirement is:
I have a form with Student_record data block. When i Click on print Button on this form. It will open another window which has Student_CSV_HELP.DESC_NAME and a check box before this.
The window look like as below:
check_box DESC_NAME+
X S_ID+
-- S_Name+
X S_Join_date+
X S_Address+
-- S_Fee+
X means check box checked.+
-- means check box Unchecked.+
After i selected these check boxes i will send 2 parameters to the report server
1. a string parameter to the report server which has the value 'S_ID,S_Join_date,S_Address' (p_column_name := 'S_ID,S_Join_date,S_Address');
2. the s_id value from the student_record block (p_S_id := '101');
Now my requirement is when i click on run. I need a report like as below:
Student ID : 101+
Joining Date : 12/17/2009 08:00:00+
Address : CA-94777+
This is nothing but the ref cursor should run like as below:
Select S_id from student_record block S_id = :p_S_id;
Select S_Join_date from student_record block S_id = :p_S_id;
Select S_Address from student_record block S_id = :p_S_id;
So, according to my understanding i have to select the columns at the run time. I dont have much knowledge in creating reports using ref cursor or dynamic sql.
So please help me to solve this issue.
Thanks in advance.Plain sql should satisfy your need. Try ....
Select S_id, S_Join_date, S_Address
from student_record
where S_id = :p_S_id -
How to use dynamic query for Result table
Hello Experts,
I want to use dynamic query and then display the result in the assignment block.
Using dynamic query BTQAct and BTQRAct and base on some search criteria i want tofilter and then append the result in the result table of that custom context node, and then it should display the result in the view in UI.
SO can you please provide me the samplle code on how to use the dynamic query and append in the result table.
Regards.Hi,
Please find below sample code:
data: query TYPE REF TO cl_crm_bol_dquery_service,
result TYPE REF TO if_bol_bo_col.
DATA: lt_params TYPE crmt_name_value_pair_tab,
lwa_params TYPE crmt_name_value_pair.
query = cl_crm_bol_dquery_service=>get_instance( 'BTQAct' ). " Get instance of dynamic query
Set general query parameter for maximum number of hits
lwa_params-name = 'MAX_HITS' .
lwa_params-value = '50'.
APPEND lwa_params TO lt_params.
query->set_query_parameters( it_parameters = lt_params ).
query->add_selection_param( iv_attr_name = 'OBJECT_ID'
iv_sign = 'I'
iv_option = 'EQ'
iv_low = <lv_objectid>
iv_high = '' ). " Set your search criteria. Repeat this code if you have multiple parameters
"You can find possible search options for a query object in GENIL_BOL_BROWSER
result ?= query->get_query_result( ). " Get result from your search query
me->typed_context-> <your result context node>->set_collection( result ).
Here you will have to create a context node in your view which would refer to query result object like for BTQAct its BTQRAct
Hope this helps.
e Regards,
Bhushan -
Finding minimum value in each row using dynamic query
need to find the minimum and maximum value from each row using dynamic query
[from curr] will be given as input
TukyDECLARE @t TABLE(a INT,b INT,c INT);
INSERT @t VALUES(1,2,3),(9,8,7),(4,6,5);
SELECT *
, ( SELECT MAX(val)
FROM (VALUES (a)
, (b)
, (c)
) AS value(val)
) AS MaxVal
, ( SELECT MIN(val)
FROM (VALUES (a)
, (b)
, (c)
) AS value(val)
) AS MinVal
FROM @t;
Best Regards,Uri Dimant SQL Server MVP,
http://sqlblog.com/blogs/uri_dimant/
MS SQL optimization: MS SQL Development and Optimization
MS SQL Consulting:
Large scale of database and data cleansing
Remote DBA Services:
Improves MS SQL Database Performance
SQL Server Integration Services:
Business Intelligence -
How to use three part name with using dynamic query.
Dear all, (sqlserver 2008 express r2)
q1)following is showing error, is it possible to accomplish the task with out using dynamic query.
DECLARE @A VARCHAR(100)
DECLARE @A1 VARCHAR(100)
SET @A='DB1'
SET @A1='DBO'
SELECT * FROM @[email protected]
q2) table value function is not accepting dynamic query , is there any way to do this task.
yours sincerleyCertain parts in an SQL query like FROM tablename cannot be local variables. In such a case, dynamic SQL can be applied:
http://www.sqlusa.com/bestpractices/dynamicsql/
As noted above, more information needed to decide if dynamic SQL the correct solution in this instance.
Kalman Toth Database & OLAP Architect
SQL Server 2014 Design & Programming
New Book / Kindle: Exam 70-461 Bootcamp: Querying Microsoft SQL Server 2012 -
Converting rows to columns using dynamic query.
I am trying to use the below code that I founnd on the web to conver rows to columns. the reason that I want to use dynamic query is that the number of rows are not know and changes.
declare
lv_sql varchar2(32767) := null ;
begin
lv_sql := 'SELECT Iplineno ';
for lv_rec in (SELECT distinct vendor from bidtabs where letting = '10021200' and call ='021')
loop
lv_sql := lv_sql
|| CHR(10)
|| ', MAX( DECODE( vendor, '
|| chr(39)
|| lv_rec.vendor
|| CHR(39)
|| ', bidprice, NULL ) ) as "'
|| lv_rec.vendor
|| '" ' ;
end loop;
lv_sql := lv_sql
|| CHR(10)
|| 'FROM bidtabs where letting = ''10021200'' and call = ''021'' and lineflag = ''L'' '
|| CHR(10)
|| 'GROUP BY iplineno ;' ;
here is the result
BIDPRICE CALL IPLINENO LETTING VENDOR
9,585 021 0010 10021200 C0104
1,000 021 0020 10021200 C0104
1,000 021 0030 10021200 C0104
17 021 0040 10021200 C0104
5 021 0050 10021200 C0104
11,420 021 0010 10021200 K0054
1,100 021 0020 10021200 K0054
1,100 021 0030 10021200 K0054
5 021 0040 10021200 K0054
3 021 0050 10021200 K0054
8,010 021 0010 10021200 V070
900 021 0020 10021200 V070
1,320 021 0030 10021200 V070
11 021 0040 10021200 V070
3 021 0050 10021200 V070
and here is the desired output
CALL IPLINENO LETTING C0104 K0054 V070
021 0010 10021200 9,585 11,420 8,010
021 0020 10021200 1,000 1,100 900
021 0030 10021200 1,000 1,100 1,320
021 0040 10021200 17 5 11
021 0050 10021200 5 3 3Here is the error message I am getting:
RA-06550: line 22, column 43:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
begin case declare end exception exit for goto if loop mod
null pragma raise return select update while with
<an identifier> <a double-quoted delimited-identifier>
<a bind variable> << close current delete fetch lock insert
open rollback savepoint set sql execute commit forall merge
pipe -
ORA-01008 with ref cursor and dynamic sql
When I run the follwing procedure:
variable x refcursor
set autoprint on
begin
Crosstab.pivot(p_max_cols => 4,
p_query => 'select job, count(*) cnt, deptno, row_number() over (partition by job order by deptno) rn from scott.emp group by job, deptno',
p_anchor => Crosstab.array('JOB'),
p_pivot => Crosstab.array('DEPTNO', 'CNT'),
p_cursor => :x );
end;I get the following error:
^----------------
Statement Ignored
set autoprint on
begin
adsmgr.Crosstab.pivot(p_max_cols => 4,
p_query => 'select job, count(*) cnt, deptno, row_number() over (partition by
p_anchor => adsmgr.Crosstab.array('JOB'),
p_pivot => adsmgr.Crosstab.array('DEPTNO', 'CNT'),
p_cursor => :x );
end;
ORA-01008: not all variables bound
I am running this on a stored procedure as follows:
create or replace package Crosstab
as
type refcursor is ref cursor;
type array is table of varchar2(30);
procedure pivot( p_max_cols in number default null,
p_max_cols_query in varchar2 default null,
p_query in varchar2,
p_anchor in array,
p_pivot in array,
p_cursor in out refcursor );
end;
create or replace package body Crosstab
as
procedure pivot( p_max_cols in number default null,
p_max_cols_query in varchar2 default null,
p_query in varchar2,
p_anchor in array,
p_pivot in array,
p_cursor in out refcursor )
as
l_max_cols number;
l_query long;
l_cnames array;
begin
-- figure out the number of columns we must support
-- we either KNOW this or we have a query that can tell us
if ( p_max_cols is not null )
then
l_max_cols := p_max_cols;
elsif ( p_max_cols_query is not null )
then
execute immediate p_max_cols_query into l_max_cols;
else
RAISE_APPLICATION_ERROR(-20001, 'Cannot figure out max cols');
end if;
-- Now, construct the query that can answer the question for us...
-- start with the C1, C2, ... CX columns:
l_query := 'select ';
for i in 1 .. p_anchor.count
loop
l_query := l_query || p_anchor(i) || ',';
end loop;
-- Now add in the C{x+1}... CN columns to be pivoted:
-- the format is "max(decode(rn,1,C{X+1},null)) cx+1_1"
for i in 1 .. l_max_cols
loop
for j in 1 .. p_pivot.count
loop
l_query := l_query ||
'max(decode(rn,'||i||','||
p_pivot(j)||',null)) ' ||
p_pivot(j) || '_' || i || ',';
end loop;
end loop;
-- Now just add in the original query
l_query := rtrim(l_query,',')||' from ( '||p_query||') group by ';
-- and then the group by columns...
for i in 1 .. p_anchor.count
loop
l_query := l_query || p_anchor(i) || ',';
end loop;
l_query := rtrim(l_query,',');
-- and return it
execute immediate 'alter session set cursor_sharing=force';
open p_cursor for l_query;
execute immediate 'alter session set cursor_sharing=exact';
end;
end;
/I can see from the error message that it is ignoring the x declaration, I assume it is because it does not recognise the type refcursor from the procedure.
How do I get it to recognise this?
Thank you in advanceThank you for your help
This is the version of Oracle I am running, so this may have something to do with that.
Oracle9i Enterprise Edition Release 9.2.0.8.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.8.0 - Production
I found this on Ask Tom (http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:3027089372477)
Hello, Tom.
I have one bind variable in a dynamic SQL expression.
When I open cursor for this sql, it gets me to ora-01008.
Please consider:
Connected to:
Oracle8i Enterprise Edition Release 8.1.7.4.1 - Production
JServer Release 8.1.7.4.1 - Production
SQL> declare
2 type cur is ref cursor;
3 res cur;
4 begin
5 open res for
6 'select * from (select * from dual where :p = 1) connect by 1 = 1'
7 using 1;
8 end;
9 /
declare
ERROR at line 1:
ORA-01008: not all variables bound
ORA-06512: at line 5
SQL> declare
2 type cur is ref cursor;
3 res cur;
4 begin
5 open res for
6 'select * from (select * from dual where :p = 1) connect by 1 = 1'
7 using 1, 2;
8 end;
9 /
PL/SQL procedure successfully completed.
And if I run the same thing on 10g -- all goes conversely. The first part runs ok, and the second
part reports "ORA-01006: bind variable does not exist" (as it should be, I think). Remember, there
is ONE bind variable in sql, not two. Is it a bug in 8i?
What should we do to avoid this error running the same plsql program code on different Oracle
versions?
P.S. Thank you for your invaluable work on this site.
Followup June 9, 2005 - 6pm US/Eastern:
what is the purpose of this query really?
but it would appear to be a bug in 8i (since it should need but one). You will have to work that
via support. I changed the type to tarray to see if the reserved word was causing a problem.
variable v_refcursor refcursor;
set autoprint on;
begin
crosstab.pivot (p_max_cols => 4,
p_query =>
'SELECT job, COUNT (*) cnt, deptno, ' ||
' ROW_NUMBER () OVER ( ' ||
' PARTITION BY job ' ||
' ORDER BY deptno) rn ' ||
'FROM emp ' ||
'GROUP BY job, deptno',
p_anchor => crosstab.tarray ('JOB'),
p_pivot => crosstab.tarray ('DEPTNO', 'CNT'),
p_cursor => :v_refcursor);
end;
/Was going to use this package as a stored procedure in forms but I not sure it's going to work now. -
Ref cursors and dynamic sql..
I want to be able to use a fuction that will dynamically create a SQL statement and then open a cursor based on that SQL statement and return a ref to that cursor. To achieve that, I am trying to build the sql statement in a varchar2 variable and using that variable to open the ref cursor as in,
open l_stmt for refcurType;
where refcurType is a strong ref cursor. I am unable to do so because I get an error indication that I can not use strong ref cursor type. But, if I can not use a strong ref cursor, I will not be able to use it to build the report based on the ref cursor because Reports 9i requires strong ref cursors to be used. Does that mean I can not use dynamic sql with Reports 9i ref cursors? Else, how I can do that? Any documentation available?Philipp,
Thank you for your reply. My requirement is that, sometimes I need to construct a whole query based on some input, and sometimes not. But the output record set would be same and the layout would be more or less same. I thought ref cursor would be ideal. Ofcourse, I could do this without dynamic SQL by writing the SQL multiple times if needed. But, I think dynamic SQL is a proper candidate for this case. Your suggestion to use lexical variable is indeed a good alternative. In effect, if needed, I could generate an entire SQL statement and place in some place holder (like &stmt) and use it as a static SQL query in my data model. In that case, why would one ever need ref cursor in reports? Is one more efficient over the other? My guess is, in the lexical variable case, part of the processing (like parsing) is done on the app server while in a function based ref cursor, the entire process takes place in the DB server and there is probably a better chance for re-use(?)
Thanks,
Murali. -
Hi..
I'm using a ref cursor query to fetch data for a report and works just fine. However i need to use dynamic sql in the query because the columns used in the where condition and for some calculations may change dynamically according to user input from the form that launches the report..
Ideally the query should look like this:
select
a,b,c
from table
where :x = something
and :y = something
and (abs(:x/:y........)
The user should be able to switch between :x and :y
Is there a way to embed dynamic sql in a ref cursor query in Reports 6i?
Reports 6i
Forms 6i
Windows 2000 PROHello Nicola,
You can parameterize your ref cursor by putting the query's select statement in a procedure/function (defined in your report, or in the database), and populating it based on arguments accepted by the procedure.
For example, the following procedure accepts a strongly typed ref cursor and populates it with emp table data based on the value of the 'mydept' input parameter:
Procedure emp_refcursor(emp_data IN OUT emp_rc, mydept number) as
Begin
-- Open emp_data for select all columns from emp where deptno = mydept;
Open emp_data for select * from emp where deptno = mydept;
End;
This procedure/function can then be called from the ref cursor query program unit defined in your report's data model, to return the filled ref cursor to Reports.
Thanks,
The Oracle Reports Team. -
Dynamic REF Cursor with Dynamic Fetch - Urgent
i have a pl/sql package with generates dynamic SQL statments. my problem is i want to open this SQL statment dynamically and fetch data in dynamic variable.
declare
type type_temp is REF CURSOR;
cur_temp type_temp;
mv_sql varchar2(4000);
begin
-- this will be dunamically generated and
-- hence could have any no. of columns.
mv_sql := select f1, f2, f3, f4 from table_temp;
open cur_temp for mv_sql;
fetch cur_temp into c1, c2, c3, c4;
close cur_temp;
end;
problem is my sql statment will have N no. of columns how can i fetch this N no. of columns.Very hard problem, because ref cursors do not (directly) support description!
Se mine (non-ideal) solution (it may be doable, but it isn't very practical
or easily maintainable):
1. "Generic" package
CREATE OR REPLACE PACKAGE dyn_fetch IS
TYPE ref_cur_t IS REF CURSOR;
g_query VARCHAR2 (32000);
g_count NUMBER;
g_desc_tab DBMS_SQL.DESC_TAB;
varchar2_type CONSTANT PLS_INTEGER := 1;
number_type CONSTANT PLS_INTEGER := 2;
date_type CONSTANT PLS_INTEGER := 12;
rowid_type CONSTANT PLS_INTEGER := 11;
char_type CONSTANT PLS_INTEGER := 96;
long_type CONSTANT PLS_INTEGER := 8;
raw_type CONSTANT PLS_INTEGER := 23;
mlslabel_type CONSTANT PLS_INTEGER := 106;
clob_type CONSTANT PLS_INTEGER := 112;
blob_type CONSTANT PLS_INTEGER := 113;
bfile_type CONSTANT PLS_INTEGER := 114;
PROCEDURE describe_columns;
FUNCTION record_def RETURN VARCHAR2;
END;
CREATE OR REPLACE PACKAGE BODY dyn_fetch IS
PROCEDURE describe_columns IS
l_cur INTEGER;
BEGIN
l_cur := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE (l_cur, g_query, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS (l_cur, g_count, g_desc_tab);
DBMS_SQL.CLOSE_CURSOR (l_cur);
EXCEPTION
WHEN OTHERS THEN
IF DBMS_SQL.IS_OPEN (l_cur) THEN
DBMS_SQL.CLOSE_CURSOR (l_cur);
END IF;
RAISE;
END;
FUNCTION record_def RETURN VARCHAR2 IS
l_record_def VARCHAR2 (32000);
l_type VARCHAR2 (100);
l_col_type PLS_INTEGER;
l_col_max_len PLS_INTEGER;
l_col_precision PLS_INTEGER;
l_col_scale PLS_INTEGER;
BEGIN
FOR i IN 1..g_count LOOP
l_col_type := g_desc_tab(i).col_type;
l_col_max_len := g_desc_tab(i).col_max_len;
l_col_precision := g_desc_tab(i).col_precision;
l_col_scale := g_desc_tab(i).col_scale;
IF l_col_type = varchar2_type THEN
l_type := 'VARCHAR2(' || l_col_max_len || ')';
ELSIF l_col_type = number_type THEN
l_type := 'NUMBER(' || l_col_precision || ',' || l_col_scale || ')';
ELSIF l_col_type = date_type THEN
l_type := 'DATE';
ELSIF l_col_type = rowid_type THEN
l_type := 'ROWID';
ELSIF l_col_type = char_type THEN
l_type := 'CHAR(' || l_col_max_len || ')';
-- ELSIF l_col_type = ...
-- long_type, raw_type ...
END IF;
l_record_def := l_record_def || ' col_' || i || ' ' || l_type || ',';
END LOOP;
l_record_def := RTRIM (l_record_def, ',');
RETURN l_record_def;
END;
END;
Note that procedure "record_def" creates columns names as col_1 (col_2 ...)
because SELECT clause in your query can be without aliases, for example
"SELECT deptno || dname FROM dept".
2. Your package which returns query nad ref cursor
CREATE OR REPLACE PACKAGE test IS
PROCEDURE set_query (p_query VARCHAR2 := NULL);
FUNCTION ref_cur RETURN dyn_fetch.ref_cur_t;
END;
CREATE OR REPLACE PACKAGE BODY test IS
PROCEDURE set_query (p_query VARCHAR2 := NULL) IS
l_query VARCHAR2 (32000) :=
' SELECT e.empno, e.ename,' ||
' e.deptno, d.dname' ||
' FROM emp e,' ||
' dept d' ||
' WHERE e.deptno = d.deptno';
BEGIN
IF p_query IS NULL THEN
dyn_fetch.g_query := l_query;
ELSE
dyn_fetch.g_query := p_query;
END IF;
END;
FUNCTION ref_cur RETURN dyn_fetch.ref_cur_t IS
l_ref_cur dyn_fetch.ref_cur_t;
BEGIN
OPEN l_ref_cur FOR dyn_fetch.g_query;
RETURN l_ref_cur;
END;
END;
Why we need two separate procedures (functions) in your package ?
a) Receiving program must use dynamic SQL, but in dynamic block we can access
only PL/SQL code elements that have global scope (standalone functions and procedures,
and elements defined in the specification of a package).
Unfortunately, cursor variables cannot be defined in the specification of a package
(cannot be global variables).
b) Receiving program must get the column list before ref cursor.
So, we have two options: call (in receiving program) the same function two times
(once to get the column list and once to return a ref cursor)
or use one procedure (or function) for returning query (to get the column list)
and second function for returning a ref cursor.
3. Your receiving program
CREATE OR REPLACE PROCEDURE test_fetch_ref_cur (p_query VARCHAR2 := NULL) IS
l_statement VARCHAR2 (32000);
FUNCTION process_def RETURN VARCHAR2 IS
l_process_def VARCHAR2 (32000);
BEGIN
l_process_def := 'DBMS_OUTPUT.PUT_LINE (';
FOR i IN 1 .. dyn_fetch.g_count LOOP
l_process_def := l_process_def || ' l_record.col_' || i || ' || ''>>'' || ';
END LOOP;
l_process_def := RTRIM (l_process_def, ' || ''>>'' || ') || ');';
RETURN l_process_def;
END;
BEGIN
test.set_query (p_query);
dyn_fetch.describe_columns;
l_statement :=
' DECLARE' ||
' TYPE record_t IS RECORD (' ||
dyn_fetch.record_def || ');' ||
' l_record record_t;' ||
' l_ref_cur dyn_fetch.ref_cur_t;' ||
' BEGIN' ||
' l_ref_cur := test.ref_cur;' ||
' LOOP' ||
' FETCH l_ref_cur INTO l_record;' ||
' EXIT WHEN l_ref_cur%NOTFOUND;' ||
process_def ||
' END LOOP;' ||
' CLOSE l_ref_cur;' ||
' END;';
EXECUTE IMMEDIATE l_statement;
END;
You can test this with:
SET SERVEROUTPUT ON;
EXECUTE test_fetch_ref_cur;
Note that we can try to use more generic solution:
CREATE OR REPLACE PACKAGE dyn_fetch IS
-- SAME AS BEFORE, PLUS:
PROCEDURE fetch_ref_cur (
p_function_ref_cur VARCHAR2,
p_process_def VARCHAR2);
END;
CREATE OR REPLACE PACKAGE BODY dyn_fetch IS
-- SAME AS BEFORE, PLUS:
PROCEDURE fetch_ref_cur (
p_function_ref_cur VARCHAR2,
p_process_def VARCHAR2)
IS
l_statement VARCHAR2 (32000);
BEGIN
l_statement :=
' DECLARE' ||
' TYPE record_t IS RECORD (' ||
record_def || ');' ||
' l_record record_t;' ||
' l_ref_cur dyn_fetch.ref_cur_t;' ||
' BEGIN' ||
' l_ref_cur := ' ||
p_function_ref_cur || ';' ||
' LOOP' ||
' FETCH l_ref_cur INTO l_record;' ||
' EXIT WHEN l_ref_cur%NOTFOUND;' ||
p_process_def ||
' END LOOP;' ||
' CLOSE l_ref_cur;' ||
' END;';
EXECUTE IMMEDIATE l_statement;
END;
END;
CREATE OR REPLACE PROCEDURE test_fetch_ref_cur (p_query VARCHAR2 := NULL) IS
FUNCTION process_def RETURN VARCHAR2 IS
-- SAME AS BEFORE
END;
BEGIN
test.set_query (p_query);
dyn_fetch.describe_columns;
dyn_fetch.fetch_ref_cur (
p_function_ref_cur => 'test.ref_cur',
p_process_def => process_def);
END;
Regards,
Zlatko Sirotic -
Using Dynamic Query in For Loop
I have a doubt whether i can use the result from dynamic query in the for loop.
for example,
declare
v_sql varchar2(1000);
v_Id INTEGER;
begin
v_sql := 'select id from table1 where id in ('||v_Id||')';
FOR i in vsql LOOP
dbms_output.put_line(i.id);
end loop;
end;
The above query is possible ?And here's a basic example of opening up a cursor for your dynamic query...
SQL> ed
Wrote file afiedt.buf
1 declare
2 v_sql varchar2(2000);
3 v_cur sys_refcursor;
4 i emp.sal%type;
5 begin
6 v_sql := 'select sal from emp';
7 open v_cur for v_sql;
8 loop
9 fetch v_cur into i;
10 exit when v_cur%NOTFOUND;
11 dbms_output.put_line('Salary: '||i);
12 end loop;
13* end;
SQL> /
Salary: 800
Salary: 1600
Salary: 1250
Salary: 2975
Salary: 1250
Salary: 2850
Salary: 2450
Salary: 3000
Salary: 5000
Salary: 1500
Salary: 1100
Salary: 950
Salary: 3000
Salary: 1300
PL/SQL procedure successfully completed.
SQL> -
Delcare Cursor using Dynamic SQL using PL/SQL in Oracle 7.3.4
In Oracle 7.3.4, can I declare a cursor at run time using Dynamic SQL. From the sample code in this website, it seems that Oracle 8 support this function. Please help. Thanks a lot.
If I can do this on Oracle 7.3.4, could you give me some sample codes? Thanks.
Regards,
RaymondHi,
Try using the the following code where you can dynamically build the Valid Select stmt. and call that where ever you want.
declare
Type Cur_ref Is Ref Cursor;
C_ref Cur_ref;
V_Str Varchar2(100);
V_Name Varchar2(100);
Begin
V_Str := 'Select Ename from Scott.emp Where empno = 7369';
Open C_Ref for V_Str;
Fetch C_ref Into V_Name;
close C_Ref;
dbms_output.put_line(V_Name);
End;
regards
gaurav
null -
Dynamic Ref Cursor with Dynamic Fetch
Hi,
I'm using dynamic sql (DBMS_SQL) to define columns of ref cursor.
It works Ok but the problem is when i'm using PL/SQL CURSOR in the REF CURSOR. Then,
I'm getting :
Error at line 3
ORA-00932: inconsistent datatypes: expected NUMBER got CURSER
ORA-06512: at "SYS.DBMS_SQL", line 1830
ORA-06512: at "TW.PRINT_REF_CURSOR", line 28
ORA-06512: at line 9
Here is my code:
set serveroutput on
exec DBMS_OUTPUT.ENABLE(1000000);
declare
l_cursor sys_refcursor;
begin
OPEN l_cursor FOR
SELECT SERVICE_TABLE.SERVICE, SERVICE_TABLE.SERVICE_GROUP, SERVICE_TABLE.SERVICE_DESC,
CURSOR(SELECT SERVICE_TABLE.SERVICE_CD FROM SERVICE_TABLE) SERVICE_CD_CURSOR
FROM SERVICE_TABLE ;
print_ref_cursor( l_cursor );
end;
=========================
CREATE OR REPLACE procedure print_ref_cursor
( p_query in out sys_refcursor,
p_date_fmt in varchar2 default 'dd-mon-yyyy hh24:mi:ss' )
is
l_theCursor integer;
l_columnValue varchar2(4000);
l_descTbl dbms_sql.desc_tab2;
l_colCnt number;
l_date date;
l_cursor SYS_REFCURSOR;
begin
l_theCursor := dbms_sql.to_cursor_number( p_query );
dbms_sql.describe_columns2
( l_theCursor, l_colCnt, l_descTbl );
-- define all columns to be cast to varchar2's, we
-- are just printing them out
for i in 1 .. l_colCnt loop
if ( l_descTbl(i).col_type in ( 12, 178, 179, 180, 181, 231 ) )
then
dbms_sql.define_column
(l_theCursor, i, l_date );
else
dbms_sql.define_column
(l_theCursor, i, l_columnValue, 4000);
end if;
end loop;
while ( dbms_sql.fetch_rows(l_theCursor) > 0 )
loop
for i in 1 .. l_colCnt loop
if ( l_descTbl(i).col_type in ( 12, 178, 179, 180, 181, 231 ) )
then
dbms_sql.column_value( l_theCursor, i, l_date );
l_columnValue := to_char( l_date, p_date_fmt );
else
dbms_sql.column_value( l_theCursor, i, l_columnValue );
end if;
dbms_output.put_line
( rpad( l_descTbl(i).col_schema_name || '.' ||
l_descTbl(i).col_name, 30 ) || ': ' || l_columnValue );
end loop;
dbms_output.put_line( '-----------------' );
end loop;
dbms_sql.close_cursor( l_theCursor );
end;
Is there a solution or bypass?
Regards,
Tamir GevaNo. The problem is that one cannot use DBMS_SQL.define_column() to define that column in the SQL projection as a cursor, and then use DBMS_SQL.column_value() to read it into a ref cursor variable.
You can however detect the cursor column - the DBMS_SQL.describe_columns3() call will return a col_type value of 102. In which case you can treat it as an exception (i.e. not process that column in the projection).
As a general issue - a cursor as a SQL column projection does not make sense to me. I have never used this in any production code. Nor do I see any reasons why.
If you want that column in the projection to contain a "list" of sorts (the results of the cursor), then a nested table type can be used as projected type and the MultiSet() function used to execute the in-line SQL and provide that SQL cursor's result as an array/nested table.
But even this approach raises the question why a standard relational join is not used?
Maybe you are looking for
-
Why are my floats not working?
Hi! Once again, I'm puzzled! Here I have two examples: http://www.doktorwear.com/test/tuotteet.htm http://www.doktorwear.com/test/tavalliset.htm On the first one, the floats for the divs that contain the images are working great. But on the second on
-
All of a sudden iPhoto is not reading my iPhone. As a result I cannot download new images. Any ideas?
-
Any standard RFC there to communicate between satellite system and Solman?
Hi Gurus, Any standard RFC there to communicate between satellite system and Solman? Thanks in advance. Regs, BBR.
-
T42 hangs, extremely slow performance
Hello, I can boot up my T42, but it works very slowly. In safe mode with networking, it works great. I have automatic updates turned on, but it cannot successfully download updates. It still has service pack 2. Not sure if that's related to slow
-
I tried all the recovery tools given to me, even backed up my files, but I did not want to restore my laptop to the out of box condition unless I have to. The disk check is fine, no errors, the memory check also, no problems found. It will restore to