| Open cursor for select, based on another cursor [message #629971] |
Thu, 18 December 2014 05:33  |
 |
OraFerro
Messages: 433 Registered: July 2011
|
Senior Member |
|
|
Hi All,
I am implementing a search function using a SP. In the search I need to search my main table and another table with 1-M relation with main table. In the result I need to out a cursor for the matching records in main table and also another cursor for the matching records in the other table with 1-M relation with the main table.
I need help for the best way to refer to the first cursor in my statement to open the second cursor as follows:
create table tst_main
(
id number primary key,
detail1 number,
detail2 varchar(10),
detail3 varchar(10)
);
create table tst_main_lk3
(
main_id number references tst_main,
main_lk_3 varchar(10),
primary key (main_id, main_lk_3)
);
CREATE OR REPLACE PROCEDURE p_test_search
( --Input Parameters
int_id IN number,
int_detail1 number,
vc_detail2 varchar,
vc_detail3 varchar,
vc_main_lk_3 varchar,
CUR_main OUT SYS_REFCURSOR
CUR_lk3 OUT SYS_REFCURSOR
)
AS
S_DB_ERROR VARCHAR2(100);
BEGIN
--the fist cursor is for records in main that match input parameters in either table tst_main or
-- table tst_main_lk3
open cur_main for
select * from TST_MAIN
where
(int_id is null or id = int_id)
AND
(int_detail1 is null or detail1=int_detail1)
AND
(int_detail2 is null or detail2=int_detail2)
AND
(int_detail3 is null or detail3=int_detail3)
AND
(vc_main_lk_3 is null or id in
(select main_id from tst_main_lk3 where main_lk_3= vc_main_lk_3));
-- The second cursor is for records in tst_main_lk3 that match the first cursor's main_id
open cur_lk3 for
select * from tst_main_lk3
where main_id in -----???? cur_main.id
EXCEPTION WHEN OTHERS THEN
--fill error varchar
--S_DB_ERROR := SQLCODE || '-' || SQLERRM;
-- call P_LOG_ERROR to log the exception error to event log table
--P_LOG_ERROR (S_APP_USER, S_DB_ERROR, S_MODULE_Name, S_PARAMS);
-- raise exception for caller
RAISE;
END;
Thanks,
Ferro
|
|
|
|
| Re: Open cursor for select, based on another cursor [message #629974 is a reply to message #629971] |
Thu, 18 December 2014 06:15   |
 |
sss111ind
Messages: 636 Registered: April 2012 Location: India
|
Senior Member |

|
|
create or replace
PROCEDURE p_test_search
( P_DEPTNO IN NUMBER,
CUR_main OUT SYS_REFCURSOR,
CUR_lk3 OUT SYS_REFCURSOR
)
AS
S_DB_ERROR VARCHAR2(100);
BEGIN
--RETURNS DATA FOR MAIN AS WELL AS SECOND TABLE
OPEN cur_main FOR
SELECT DEPTNO FROM emp WHERE DEPTNO=P_DEPTNO --SECOND TABLE
UNION ALL
SELECT DEPTNO FROM DEPT WHERE DEPTNO=P_DEPTNO;--MAIN TABLE
--RETURNS DATA FOR MAIN TABLE ONLY(how many records first cursor have returned for main same record will be returned)
OPEN cur_lk3 FOR
SELECT DEPTNO FROM DEPT WHERE DEPTNO=P_DEPTNO;
EXCEPTION WHEN OTHERS THEN
RAISE;
END;
var x refcursor;
var y refcursor;
set autoprint on;
BEGIN
p_test_search(10,:x,:y);
end;
[Updated on: Thu, 18 December 2014 06:18] Report message to a moderator
|
|
|
|
|
|
|
|
|
|
| Re: Open cursor for select, based on another cursor [message #629981 is a reply to message #629979] |
Thu, 18 December 2014 06:53   |
 |
sss111ind
Messages: 636 Registered: April 2012 Location: India
|
Senior Member |

|
|
You cant directly access it as suggested by CookieMonster, but You can do like this
create or replace
PROCEDURE p_test_search
( p_loc IN vARCHAR2,
CUR_main OUT SYS_REFCURSOR,
CUR_lk3 OUT SYS_REFCURSOR
)
AS
S_DB_ERROR VARCHAR2(100);
l_deptno number;
BEGIN
--RETURNS DATA FOR MAIN table
OPEN cur_main FOR
SELECT * FROM DEPT WHERE loc=p_loc;--MAIN TABLE
SELECT DEPTNO into l_deptno FROM DEPT WHERE loc=p_loc;
--RETURNS DATA FOR other TABLE
OPEN cur_lk3 FOR
SELECT * FROM emp WHERE DEPTNO=l_deptno;
EXCEPTION WHEN OTHERS THEN
RAISE;
END;
var x refcursor;
var y refcursor;
set autoprint on;
BEGIN
p_test_search('DALLAS',:x,:y);
end;
[Updated on: Thu, 18 December 2014 06:54] Report message to a moderator
|
|
|
|
|
|
|
|
|
|
|
|
| Re: Open cursor for select, based on another cursor [message #630099 is a reply to message #630090] |
Sat, 20 December 2014 05:27   |
 |
OraFerro
Messages: 433 Registered: July 2011
|
Senior Member |
|
|
Hi All,
SUMMARY of the problem: the reason I am trying to return several cursors in one SP is that I need to fill search result into a grid in my application and instead of returning the whole set of data (the main rows and all it 1:M rows in one query and adjust the result in the application side, I am trying to make oracle return the main rows alone, and then each of the 1:M rows separately). This way the application will fill the search result grid with the main rows and loop over them to fill combo boxes for each 1:M field that it gets from each cursor.
I had a new trial that is working but I am not sure if this is the right way to do it or not (best practice point of view).
In the real case I have 34 search parameters in the where condition of the 1st (main) cursor. Also the second cursor is actuall 4 cursors (1:M) that should all be returned to fill the grid in my application.
This is why I was thinking of a way to open the secondary cursors based on the 1st (main) cursor.
open cur_lk3 for
select * from tst_main_lk3
where main_id in -----???? cur_main.id
I learned that a cursor is only a pointer to a query so it can't be used this way, so I had two alternatives:
1- use the same where condition in a normal select statement for the 1:M cursors (ref CraigB reply on Thu, 18 December 2014 08:51 )
2- my current trial which is based on:
2.1 declare a table variable of main table after declaring a type
2.2 declare a string that will hold the IN clause for the 1:M cursor
2.3 create the table after fetching and looping over the cursor
2.4 looping over the table to construct the in clause as a string
2.5 remove the last comma in the in clause string
2.6 use the in clause string in each 1:M cursor
TYPE doc_type
IS TABLE OF arc_tst_main%ROWTYPE INDEX BY PLS_INTEGER;
l_doc doc_type;
s_doc_serial_in varchar2(1000);
LOOP
FETCH cur_main BULK COLLECT INTO l_doc;
EXIT WHEN CUR_DOCUMENT%NOTFOUND;
END LOOP;
--loop over the table l_doc to construct the in clause string
FOR indx IN 1 .. l_doc.count
LOOP
s_doc_serial_in := s_doc_serial_in || l_doc(indx).document_serial ||',';
END LOOP;
--Remove the extra comma at the end for the string
s_doc_serial_in := SUBSTR (s_doc_serial_in, 0, LENGTH(s_doc_serial_in)-1) ;
OPEN cur_lk3 for
select * from tst_main_lk3
where main_id in (s_doc_serial_in);
--...repeat the same for the rest of the 1:M cursors
Please give your recommendation and any other ideas or corrections.
Ferro
[Updated on: Sat, 20 December 2014 05:44] Report message to a moderator
|
|
|
|
| Re: Open cursor for select, based on another cursor [message #630104 is a reply to message #630099] |
Sat, 20 December 2014 06:31   |
 |
sss111ind
Messages: 636 Registered: April 2012 Location: India
|
Senior Member |

|
|
In oracle "In" will not support more than 1000 .So if your string contains more than this then it results an error. You could do it easily if you join the main and secondary table to return the all the cursors. If no direct join is there then use same where clause everywhere from top to bottom.
create or replace
PROCEDURE p_test_search
( p_loc IN VARCHAR2,--first table search
p_job in VARCHAR2,--second table search
CUR_main OUT SYS_REFCURSOR,
CUR_lk3 OUT SYS_REFCURSOR
)
AS
S_DB_ERROR VARCHAR2(100);
l_deptno number;
BEGIN
for i in ( SELECT * FROM dept WHERE loc=p_loc) loop --main cursor
dbms_output.put_line(i.deptno); --main cursor data
FOR j IN (SELECT * FROM emp WHERE DEPTNO=i.deptno AND job=p_job) loop --passing main cursor data and parameter data
dbms_output.put_line('ccc'|| j.deptno||' '||j.ename); --getting second cursor data
end loop;
end loop;
-- the same process as above but needs to returned as cursor
OPEN CUR_main
for select * from dept where loc=p_loc; --main cursor data
--first secondary cursor
OPEN CUR_lk3 FOR
SELECT * FROM dept,emp WHERE emp.deptno=dept.deptno -- second cursor data (main table join with second table)
and dept.loc=p_loc AND job=p_job;
END;
var x refcursor;
var y refcursor;
set autoprint oN;
BEGIN
p_test_search('SALES','SALESMAN',:x,:y);
END;
[Updated on: Sat, 20 December 2014 06:53] Report message to a moderator
|
|
|
|
|
|