Home » SQL & PL/SQL » SQL & PL/SQL » Open cursor for select, based on another cursor (11.2.0.1.0)
Open cursor for select, based on another cursor [message #629971] Thu, 18 December 2014 05:33 Go to next message
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 Go to previous messageGo to next message
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 #629976 is a reply to message #629974] Thu, 18 December 2014 06:24 Go to previous messageGo to next message
OraFerro
Messages: 433
Registered: July 2011
Senior Member
Thanks sss111ind but this is not what I want.

I want the 1st cursor to return only the results for the matching records in main table only and the second cursor to return the matching records in the table.

My problem is in how to refer to the 1st cursor (of the main table) in the select statement that opens the second cursor.

THanks,
Ferro
Re: Open cursor for select, based on another cursor [message #629978 is a reply to message #629976] Thu, 18 December 2014 06:45 Go to previous messageGo to next message
sss111ind
Messages: 636
Registered: April 2012
Location: India
Senior Member

First cursor will return main table data exactly.And in the second cursor what you really want to refer from the first cursor.
Re: Open cursor for select, based on another cursor [message #629979 is a reply to message #629976] Thu, 18 December 2014 06:47 Go to previous messageGo to next message
cookiemonster
Messages: 13975
Registered: September 2008
Location: Rainy Manchester
Senior Member
You can't.
Re: Open cursor for select, based on another cursor [message #629981 is a reply to message #629979] Thu, 18 December 2014 06:53 Go to previous messageGo to next message
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 #629988 is a reply to message #629981] Thu, 18 December 2014 08:19 Go to previous messageGo to next message
Michel Cadot
Messages: 68776
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator

EXCEPTION WHEN OTHERS THEN 

RAISE;


This is completely silly.
Read WHEN OTHERS.

 SELECT DEPTNO into l_deptno FROM DEPT WHERE loc=p_loc;    


And if the first query returns several rows?

Re: Open cursor for select, based on another cursor [message #629995 is a reply to message #629988] Thu, 18 December 2014 08:51 Go to previous messageGo to next message
CraigB
Messages: 386
Registered: August 2014
Location: Utah, USA
Senior Member
I think the problem is that you are incorrectly referencing your CUR_MAIN.main_id.

You wrote:
open cur_lk3 for 
      select * from tst_main_lk3
      where main_id in -----???? cur_main.id

Shouldn't it be:
open cur_lk3 for 
      select * from tst_main_lk3
      where main_id = cur_main.main_id

You can't do an "IN" comparison because your CUR_MAIN.MAIN_ID represents a single value not a series of values. If the whole purpose of the first CURSOR is to filter the results of your 2nd CURSOR I think this would work...
 1: select * 
 2:   from tst_main_lk3
 3:  where main_id in (select main_id 
 4: 		     from TST_MAIN
 5: 		    where (int_id is null or id = int_id)
 6:		      AND (int_detail1 is null or detail1=int_detail1)
 7:		      AND (int_detail2 is null or detail2=int_detail2)
 8:		      AND (int_detail3 is null or detail3=int_detail3)
 9:		      AND (   vc_main_lk_3     is null 
10:			   or id in (select main_id from tst_main_lk3 where main_lk_3= vc_main_lk_3))
11:		  ); 

Craig...
Re: Open cursor for select, based on another cursor [message #630089 is a reply to message #629995] Sat, 20 December 2014 02:10 Go to previous messageGo to next message
OraFerro
Messages: 433
Registered: July 2011
Senior Member
Hi CraigB,

This is the solution is what I have now as the best I can get, however the first cursor output is needed (only matching records from main table in order to fill the main grid in my application search page) and also the second cursor is needed (to fill a combo box in the same grid that represents the 1:M relation in each row in the grid).

The purpose of the post was trying to find an alternative to repeating the whole search query and linking main to lk in the second cursor's query, but it seems not possible unless there is another idea.

Thanks a lot
Ferro
Re: Open cursor for select, based on another cursor [message #630090 is a reply to message #630089] Sat, 20 December 2014 02:12 Go to previous messageGo to next message
OraFerro
Messages: 433
Registered: July 2011
Senior Member
Dear Cookiemonster,

Quote:
You can't.

Thanks for the precise and short reply.

Ferro
Re: Open cursor for select, based on another cursor [message #630099 is a reply to message #630090] Sat, 20 December 2014 05:27 Go to previous messageGo to next message
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 Go to previous messageGo to next message
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

Re: Open cursor for select, based on another cursor [message #630105 is a reply to message #630104] Sat, 20 December 2014 07:39 Go to previous message
Michel Cadot
Messages: 68776
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator

Stop digging the correct has been providing by Cookiemonster: you can't.
Your answer is wrong.

Previous Topic: I tried , adn tried, and tried, and for that reason, I'm notgoint to give up...
Next Topic: DatatypeConverter
Goto Forum:
  


Current Time: Mon Aug 24 02:26:13 CDT 2026