I have a parameterized cursor "cur_lovs(parm1, parm2, parm3)"
I want to loop and inside the loop, I wanna use the same cursor "cur_lovs(parm1, parm2, valOfMainLoop)" with the values getting from main loop.
If I try this I am getting the below error:
ORA-06511: PL/SQL: cursor already open
is there any way to do this?
The error is self explanatory. You can not reuse the cursor whilst it is still open, but you can always close it and open it back up.
If you want to use a cursor within a cursor loop, you'll need another cursor.
Related
I have an oracle pl/sql anonymous block with an implicit cursor in a for loop that is nested on a for loop in this way:
FOR secuence IN 1..3 LOOP
FOR registro_notificacion IN (
SELECT 'data' FROM my_table WHERE my_table.column1=secuence)
LOOP
--work with data
END LOOP; END LOOP;
The problems occurs when I have values returned on secuence=1 and empty on the others because for some reason the implicit cursor doesn´t clean itself.
So, on the secuence=2 im suposed to don't do nothing because there is no data, but for some reason it still have the data returned on the first loop (secuence=1).
Should I declare and explicit cursor to close at the end of every iteration? Although I consider to use 3 for loops, one for every secuence value but that its not the idea I guess.
I use cursor for-loops all the time and have never seen the situation you describe. The only thing I can think is that you have a variable named secuence declared elsewhere in your program that happens to be set to 1. In this case, the PL/SQL compiler may be choosing to use the global variable secuence rather than the loop-control variable secuence when generating the SQL statement. A good rule of thumb is to use a unique name for each loop-control variable.
However, you can get rid of the FOR secuence... loop entirely by using:
FOR registro_notificacion IN (SELECT 'data'
FROM my_table
WHERE my_table.column1 BETWEEN 1 AND 3
ORDER BY my_table.column1)
LOOP
--work with data
END LOOP;
Opening one cursor is generally less costly than opening three cursors.
Best of luck.
Please see the below procedure. I did not close cursor and it is working fine. Am I missing something here.
Is it mandatory to close cursor or Oracle closes it automatically?
CREATE OR REPLACE PROCEDURE pr_cursor_test IS
CURSOR emp_cur IS SELECT empno, ename FROM emp;
emprec emp_cur%rowtype;
BEGIN
OPEN emp_cur;
LOOP
FETCH emp_cur INTO emprec;
EXIT WHEN
emp_cur%notfound;
--Do Something
dbms_output.put_line(emprec.ename);
END LOOP;
END;
This article on Oracle website is pretty clear about it.
When you declare a cursor in a package (that is, not inside a
subprogram of the package) and the cursor is opened, it will stay open
until you explicitly close it or your session is terminated.
When the cursor is declared in a declaration section (and not in a
package), Oracle Database will also automatically close it when the
block in which it is declared terminates. It is still, however, a good
idea to explicitly close the cursor yourself. If the cursor is moved
to a package, you will have the now necessary CLOSE already in place.
And if it is local, then including a CLOSE statement will also show
other developers and your manager that you are paying attention.
In your code example CURSOR is declared as part of procedure (not as part of package), which means, cursor is closed automatically when procedure executioin is complete. However it is best coding practice to CLOSE cursor statement if you have OPEN cursor statement in code. It makes code easy to understand and support in future.
I have a PL/SQL package where i want to declare a select-statment which are used by different other Packages. So i see to ways. First way i define a cursor which can be called from other packages and store the select. Second way would be a procedure which stored the select.
Can someone tell me the advantages and disadvantages of each way? My Prof. say Cursor are old and statefull and noone use this today. My Chef tell me Cursor is faster to iterate and you can make Types of it.
Can someone tell me what's the best practice here?
For example:
CURSOR crs_active_customer IS
SELECT * FROM customer where status = 'active'
OR
PROCEDURE prc_getActiveCustomer IS
BEGIN
SELECT * FROM customer where status = 'active';
END prc_getActiveCustomer;
What is better way to store select-statements.
I would write a function that returns a new cursor instance every time you call it. A cursor variable in a package is actually a GLOBAL variable: you can have only one procedure at a time using it. This is probably the problem your professor is referring to.
Having a global cursor means that you will run into "cursor already open" errors if you write a a procedure that, while scanning the results of such cursor calls another function that internally needs to use the same cursor.
PL/SQL 101 to the rescue ! From Working with Cursors:
The central purpose of the Oracle PL/SQL language is to make it as easy and efficient as possible to query and change the contents of tables in a database. You must, of course, use the SQL language to access tables, and each time you do so, you use a cursor to get the job done.
So every time you have SQL in PL/SQL there will be a cursor. The next question is what kinds of cursors there is and when to use them. The above mentioned article touches also this topic.
You can also read the fine manual: Cursors
A cursor is a pointer to a private SQL area that stores information about processing a specific SELECT or DML statement.
And then carry on reading about implicit and explicit cursors.
Next find a better professor.
In our application, we call various stored procedures that return reference cursors in the following fashion:
SELECT foo_package.sp_Bar('arg1', 'arg2', 'arg3', 'arg4') FROM dual;
What the wrap_xml function does is to convert the cursor result to an XML type, which will then be used in the application. After the conversion, it immediately closes the cursor (this step has solved memory issues for us before).
FUNCTION wrap_xml (c_result SYS_REFCURSOR)
RETURN XMLTYPE
IS
xml_val XMLTYPE;
BEGIN
xml_val := xmltype.CreateXML (c_result);
IF c_result%ISOPEN
THEN
CLOSE c_result;
END IF;
RETURN xml_val;
END;
In most cases, this appears to work fine: the XML is created and the cursors are closed. However, since introducing a stored procedure that opens a cursor for a dynamic query, we are observing a rapid increase in open cursors, eventually leading to:
ORA-01000: maximum open cursors exceeded
The dynamic query is built in order to "simulate" the results returned from other cursors, for testing purposes. For example, the stored procedure would build a dynamic query like this:
SELECT '1' as "COLUMN1", '990' as "COLUMN2", 'N' as "COLUMN3", NULL as "COLUMN5" FROM dual;
It would then open a cursor for this query string, and return the cursor:
OPEN rc_return FOR v_sql_query;
RETURN rc_return;
The resulting reference cursor is again passed to the wrap_xml function above, which I would expect to close the cursor – just like it does any other cursor. However, this doesn't seem to be the case, as the number of open cursors just keeps on growing. What could be the reason for this?
Additional investigation:
Stepping through the wrap_xml function, I can see the program flow skipping over the body of the c_result%ISOPEN check, implying that the cursor has indeed been closed. Yet it appears that the open cursor count still increases!
We appear to have plugged the leak by removing the ISOPEN check from the wrap_xml function and just executing the close cursor command in all cases. Apparently the ISOPEN flag is not set on cursors opened for dynamic SQL queries.
I am, however, unable to find a reference for this. Can anyone back this up?
I'm having some troubles executing oracle stored procedure from package.
I've intalled PL/SQL developer on local machine, and when I try to test procedure I get generated code like this:
begin
-- Call the procedure
owner.mypackage.getallrequests(res => :res,
id=> :id);
end;
But I can't modify this query to return me data. Would really appreciate help.
Assuming you've got to this point by right-clicking on the procedure in the object explorer and choosing 'test', you'll have a Test Window with the anonymous PL/SQL block you showed. You haven't said, but I assume id is an in variable, and res is the out cursor variable. In the variable section in the bottom half of the window, type in the ID value you're searching for, then execute it (clicking the gear, or hitting F8).
Nothing obvious will change if those are the only variables; non-cursor out or in out variables would be highlighted in yellow if their values had changed, but the cursor is not, and in variables by definition won't have changed.
At the far right of the res cursor variable in the bottom of the test window, there's a small button with ... in it, which the help pages refer to as the 'cell button'. Click that, and a new window will open showing the cursor result set.