Is it possible to open cursor which is in package in another procedure? - sql

Just a thought,Is it possible to open cursor which is in package in another procrdure?
example : pack_name has a procedure myprocedure. The cursor opened in this procedure can be opened in another procedure ?
i.e can OPEN LV_TEST_CUR FOR LV_QUERY; be written in another procedure ?
create or replace package pack_name
is
create or replace
PROCEDURE myprocedure
AS
LV_TEST_CUR SYS_REFCURSOR;
LV_QUERY VARCHAR2(200);
LV_DATE DATE;
BEGIN
LV_QUERY:='select sysdate as mydate from dual';
END myprocedure;
end pack_name;

Why would you want to? It doesn't really make sense to define the query used for a ref cursor in one package's procedure and then to open it in a completely different package's procedure.
Sure it's possible (although your attempt won't work) - you'd just be passing around the string containing the select statement you want to use to open your ref cursor - but it's not the best design. For a start, you're now stuck using dynamic sql, when you might otherwise have been able to open the ref cursor with static sql (dynamic sql is only checked at runtime, not at compile time, so you won't know about any syntax errors until you try to open the cursor).
In general, I would stick to opening the ref cursor in the same place as it was defined.

Related

Executing a stored procedure inside another stored procedure using Select Query

I want to call a stored procedure on every row of a table inside my own stored procedure. In SQL Developer workspace I can simple call it like this:
SELECT my_stored_proc(...)
FROM my_table
However in my stored procedure this doesn't seem to execute:
stmt := 'SELECT my_stored_proc(...) FROM my_table';
EXECUTE IMMEDIATE stmt;
This does work:
DECLARE
l_cursor sys_refcursor;
BEGIN
OPEN l_cursor FOR stmt;
LOOP
FETCH l_cursor INTO ...;
EXIT WHEN l_cursor%NOTFOUND;
my_stored_proc(...);
END LOOP;
...
My question is why is this happening.
The behaviour in your second example is explicitly covered in a prominent note in the documentation:
If dynamic_sql_statement is a SELECT statement, and you omit both into_clause and bulk_collect_into_clause, then execute_immediate_statement never executes. For example, this statement never increments the sequence:
EXECUTE IMMEDIATE 'SELECT S.NEXTVAL FROM DUAL'
Which is essentially what you are doing. Because you don't select the result of your procedure (or, in fact your function) into a variable, the query is not executed, so the function is not called.
As you have multiple rows in your table you can't select into a scalar variable, though you could bulk collect into a collection; or use a cursor as you do in your third example. (Although, if the cursor is being opened with the same statement, you seem to be calling the function twice for each row - once when the query is executed, and then again inside the PL/SQL loop. I'm probably reading too much into your contrived example...)
The answer is simple, yet complicated, and many beginner PLSQL developers seem to not be able to get a grasp on the whole concept of cursors...
Your
SELECT my_stored_proc(...)
FROM my_table
in your SQL Developer executes OK because your SQL Developer opens a cursor for your query, fetches the cursor into your data grid, then closes the cursor.
Your
stmt := 'SELECT my_stored_proc(...) FROM my_table';
EXECUTE IMMEDIATE stmt;
inside a stored procedure fails for the same reason - it opens a cursor for the dynamic SQL, yet it does not have any PLSQL variable to fetch the cursor's results into. If you want to select something, you need to
either open a cursor for it, fetch the data into a PLSQL variable in a loop (and do whatever you want to do with the fetched data), then close the cursor,
or to select/bulk select the query results into a PLSQL variable (and then do whatever you want to do with the fetched data).
... which is what you did in your third code snippet.

How to execute an oracle procedure with an out sys_refcursor parameter?

I have a proc in my package body:
create or replace package body MYPACKAGE is
procedure "GetAllRules"(p_rules out sys_refcursor)
is
begin
open p_rules for
select * from my_rules;
end "GetAllRules";
-- etc
And I'm exposing this in my package spec.
How do I execute this procedure in a new SQL Window in PL SQL Developer (or similar)?
You can execute the procedure relatively easily
DECLARE
l_rc sys_refcursor;
BEGIN
mypackage."GetAllRules"( l_rc );
END;
Of course, that simply returns the cursor to the calling application. It doesn't do anything to fetch the data from the cursor, to do something with that data, or to close the cursor. Assuming that your goal is to write some data to dbms_output (which is useful sometimes for prototyping but isn't something that production code should be relying on), you could do something like
DECLARE
l_rc sys_refcursor;
l_rec my_rules%rowtype;
BEGIN
mypackage."GetAllRules"( l_rc );
LOOP
FETCH l_rc INTO l_rec;
EXIT WHEN l_rc%NOTFOUND;
dbms_output.put_line( <<print data from l_rec>> );
END LOOP;
CLOSE l_rc;
END;
If you're really doing something like this with the cursor in PL/SQL, I'd strongly suggest returning a strongly-typed ref cursor rather than a weakly-typed one so that you can declare a record in terms of the cursor's %rowtype rather than forcing the caller to know exactly what type to declare and hoping that the query in the procedure doesn't change. This also requires you to explicitly write code to display the data which gets annoying.
If you're using SQL*Plus (or something that supports some SQL*Plus commands), you can simplify things a bit
VARIABLE rc REFCURSOR;
EXEC mypackage."GetAllRules"( :rc );
PRINT :rc;
As an aside, I'm not a fan of using case-sensitive identifiers. It gets very old to have to surround identifiers like "GetAllRules" with double-quotes every time you want to call it. Unless you have really compelling reasons, I'd suggest using standard case-insensitive identifiers. It's perfectly reasonable to capitalize identifiers reasonably in your code, of course, it just doesn't make a lot of sense to go to the effort of forcing them to be case-sensitive in the data dictionary.

Using a PL/SQL stored procedure in Crystal Report command object

I'd like to call a stored procedure from a crystal report command object using an Oracle direct connection. The stored procedure takes a refcursor and some parameters that can be passed from the report, but I'm not sure what the syntax should look like.
For simplicity, feel free to pretend that the stored procedure only takes a refcursor and nothing else. What should the syntax look like? I assume I need to declare the refcursor, call the SP, and then return the cursor.
I'm pretty unfamiliar with this stuff though, and I'm not actually sure how to return the cursor. I figure the first bit would look like:
VARIABLE Cursor refcursor
declare
begin
MYSTOREDPROCEDURE(:Cursor);
end;
/
I'm not sure how to then return the cursor for Crystal Reports to use (2008/2011). I hope this was enough information.
You can't call a stored procedure from a command. You need to add it to the report in the same manner as you add a table (in the database expert). Moreover, the SP needs to be built a certain way to work with CR; specifically, it needs to return a REF CURSOR.
Example.

how to excecute a simple oracle procedure with out parameter

I am new to oracle procedures so I'm having a bit of trouble with this. I have an oracle procedure defined like
PROCEDURE USERPROGRESS (
queryType IN varchar2,
o_Cursor OUT cur_Cursor) IS ...
Notice how it has the out cur_Cursor. At the end of the procedure the procedure does
OPEN o_Cursor FOR sql_string;
How exactly do I can I call this procedure? I'm having trouble finding any helpful examples. Thanks.
Check this link..
http://www.oracle-base.com/articles/misc/UsingRefCursorsToReturnRecordsets.php
Depending on how you declared cur_Cursor, you can define a variable in your procedure and then fetch and display the results as needed.

Difference between "IN" and "IN OUT" CURSOR parameter in Oracle

From Oracle:
"When you declare a cursor variable as the formal parameter of a subprogram that fetches from the cursor variable, you must specify the IN or IN OUT mode. If the subprogram also opens the cursor variable, you must specify the IN OUT mode."
But, I can code that (only OUT parameter):
create or replace procedure mycur_out(mc OUT mycurpkg.mytypecur) as
begin
open mc for select * from mytable;
end mycur_out;
and works equal to (IN OUT parameter)
create or replace procedure mycur_inout(mc IN OUT mycurpkg.mytypecur)
as
begin
open mc for select * from table10;
end mycur_inout;
Also, It's work fine with dynamic cursor too:
create or replace procedure mycur_out_ref(mc out mycurpkg.mytyperefcur)
as
begin
open mc for 'select * from table10';
end mycur_out_ref;
I've tested the 3 cases directly from oracle and from VB6 with ADO, and no problems.
So, in that cases, is there any difference between IN using just "OUT" and "IN OUT" cursors parameters?
UPDATE
The reason I'm asking:
We read data using routines similar
to the examples (just open the
cursors). The cursor parameters
always are "IN OUT" (Don't ask me
why, I'm trying to figure out)
The routines are invoked with ADO/VB6
Now, we are trying to use some of the routines from JDBC, but the
adapter apparently just accepts OUT
parameters in this cases.
Finally, the main reason, I want to change the cursor parameters on DB
routines to only OUT, but first I
want to know the collaterals effects
of that change.
Thanks!
In the text you quote from the manual, note that it is specifically talking about "a subprogram that fetches from the cursor variable". None of your examples do this, so the quote is not relevant to them.
However, it nonetheless appears that there's nothing wrong with using OUT only in such a situation, if the subprogram both opens and fetches from the cursor variable:
SQL> variable c refcursor
SQL> set serveroutput on
SQL> create or replace procedure no_good (c OUT sys_refcursor)
2 as
3 my_dummy dual.dummy%type;
4 begin
5 open c for select dummy from dual union all select dummy from dual;
6 fetch c into my_dummy;
7 dbms_output.put_line( my_dummy );
8 end;
9 /
Procedure created.
SQL> exec no_good( :c )
X
PL/SQL procedure successfully completed.
SQL> print c
D
-
X
I think the the text is actually trying to make two points that are somewhat independent of each other. Firstly, if you want to pass any already-opened cursor variable into a subprogram, which will fetch from it, the parameter must be declare IN or IN OUT. Secondly, if you want to pass a cursor variable into a subprogram, which will then open it, the parameter must be declared OUT or IN OUT. This is true regardless of whether you actually care about passing the value of the cursor variable back to the caller:
SQL> create or replace procedure no_good (c IN sys_refcursor)
2 as
3 my_dummy dual.dummy%type;
4 begin
5 open c for select dummy from dual;
6 fetch c into my_dummy;
7 dbms_output.put_line( my_dummy );
8 close c;
9 end;
10 /
Warning: Procedure created with compilation errors.
SQL> show error
Errors for PROCEDURE NO_GOOD:
LINE/COL ERROR
-------- -----------------------------------------------------------------
5/6 PL/SQL: SQL Statement ignored
5/11 PLS-00361: IN cursor 'C' cannot be OPEN'ed
This error can be fixed by changing the parameter mode, but actually it would seem to make more sense to simply make the cursor variable a local variable rather than a parameter.
If I understand the question right, the difference is that with the IN OUT version you can pass in a cursor from outside the procedure, and then change that variable (similar to the difference between OUT and IN OUT for a simple numeric variable).
The OUT parameter cursor starts out as a NULL value / closed cursor.
The IN OUT parameter version starts with whatever state is passed in from outside.
You may want to retry your procedure calls repeatedly passing in the same cursor variable - the OUT version should replace the existing value, the IN OUT version should give an exception on the second time round that you are trying to open an open cursor.
Another thing the IN OUT approach allows, that the OUT approach does not, is to take action based on the passed in cursor, and change the returned cursor.
PROCEDURE lp_test2 (mc IN OUT mycurpkg.mytypecur)
IS
lr table10%ROWTYPE;
BEGIN
IF mc%ISOPEN THEN
FETCH mc INTO lr;
IF mc%NOTFOUND THEN
CLOSE mc;
/* Switch cursor to alternative table */
open mc for select * from schema2.table10;
END IF;
END IF;
END lp_test2;
I am just struggling to think of a real situation where you might want to (take in a cursor variable, cast it back into a SQL statement, append some extra dynamic SQL, and return the whole lot back as the same cursor??).