Invalid cursor when fetch - oracle

I can't execute this anonymous procedure, when I fetch the cursor c_ev I get an invalid cursor error.
The source code of the anonymous procedure and the stored code are here:
CREATE OR REPLACE
PROCEDURE jorge_ResulPartidosPorJornada (p_cod_jor integer,C_partidos OUT SYS_REFCURSOR, C_EV OUT SYS_REFCURSOR) AS
BEGIN
OPEN C_EV FOR
SELECT P.RESULTADOEV, E.NOMBRE
FROM PARTIDOS P, EQUIPOS E
WHERE P.JORNADA_COD=P_COD_JOR
AND P.CODEQUIPO_VISITANTE=E.COD;
CLOSE C_EV;
END;
declare
C_PARTIDOS SYS_REFCURSOR;
C_EL SYS_REFCURSOR;
R_EV PARTIDOS.RESULTADOEV%TYPE;
N_EV EQUIPOS.NOMBRE%TYPE;
jornada integer;
begin
jornada:= 1;
jorge_ResulPartidosPorJornada(jornada, C_PARTIDOS,C_EV);
FETCH C_EV INTO R_EV,N_EV;
WHILE C_EV%FOUND LOOP
dbms_output.put_line(R_EV);
FETCH C_EV INTO R_EV,N_EV;
END LOOP;
END;

Mistake you made was when you closed the cursor in jorge_something procedure.
If you don't (I used Scott's sample tables as I don't have yours), it works:
SQL> create or replace procedure jorge
2 (p_cod_jor in integer,
3 c_partidos out sys_refcursor,
4 c_ev out sys_refcursor
5 )
6 as
7 begin
8 open c_ev for --> don't close it!
9 select empno, ename from emp where deptno = 10;
10 end;
11 /
Procedure created.
SQL> declare
2 c_partidos sys_refcursor;
3 c_el sys_refcursor;
4 r_ev emp.empno%type;
5 n_ev emp.ename%type;
6 jornada integer;
7 begin
8 jornada := 1;
9 jorge (jornada, c_partidos, c_el);
10
11 loop
12 fetch c_el into r_ev,n_ev;
13 exit when c_el%notfound;
14 dbms_output.put_line(r_ev ||' '|| n_ev);
15 end loop;
16 end;
17 /
7782 CLARK
7839 KING
7934 MILLER
PL/SQL procedure successfully completed.
SQL>
If you do close it, it won't work:
SQL> create or replace procedure jorge
2 (p_cod_jor in integer,
3 c_partidos out sys_refcursor,
4 c_ev out sys_refcursor
5 )
6 as
7 begin
8 open c_ev for
9 select empno, ename from emp where deptno = 10;
10 close c_ev;
11 end;
12 /
Procedure created.
SQL> declare
2 c_partidos sys_refcursor;
3 c_el sys_refcursor;
4 r_ev emp.empno%type;
5 n_ev emp.ename%type;
6 jornada integer;
7 begin
8 jornada := 1;
9 jorge (jornada, c_partidos, c_el);
10
11 loop
12 fetch c_el into r_ev,n_ev;
13 exit when c_el%notfound;
14 dbms_output.put_line(r_ev ||' '|| n_ev);
15 end loop;
16 end;
17 /
declare
*
ERROR at line 1:
ORA-01001: invalid cursor
ORA-06512: at line 12
SQL>
By the way, your code won't work anyway. You declared C_EL and used C_EV
C_EL SYS_REFCURSOR;
jorge_ResulPartidosPorJornada(jornada, C_PARTIDOS, C_EV);
^^^^
should be C_EL
but that's probably just a typo.

Related

How to return more than one select queries in same procedure

I would like to ask how can i print output in procedure more than one statement.
Assume that you want to show dba_objects and segments row count. But i can not use dbms_sql.return_result my version is 11g.
Something like,
create or replace procedure get_rows_count
(
cursor1 out SYS_REFCURSOR,
cursor2 out SYS_REFCURSOR
)
as
begin
open cursor1 for select count(*) from dba_objects;
open cursor2 for select count(*) from dba_segments;
end get_rows_count;
/
Assume that you want to show dba_objects and segments row count
I assumed it. Conclusion: that's not the way to do it. If you want to get row count from e.g. dba_objects, then you should just
select count(*) from dba_objects;
in any variation you want (pure SQL, function that returns that number, procedure with an OUT parameter (worse option), ...). But, creating a procedure which uses ref cursor for that purpose is ... well, wrong.
If I got you wrong, then: procedure you wrote is OK. You can call it from another PL/SQL procedure (named or anonymous), fetch result into a variable and do something with it (e.g. display it).
Your procedure (selects from Scott's tables; I don't have access to DBA_ views):
SQL> CREATE OR REPLACE PROCEDURE get_rows_count (cursor1 OUT SYS_REFCURSOR,
2 cursor2 OUT SYS_REFCURSOR)
3 AS
4 BEGIN
5 OPEN cursor1 FOR SELECT * FROM emp;
6
7 OPEN cursor2 FOR SELECT * FROM dept;
8 END get_rows_count;
9 /
Procedure created.
How to call it? See line #8:
SQL> SET SERVEROUTPUT ON
SQL>
SQL> DECLARE
2 rc1 SYS_REFCURSOR;
3 rc2 SYS_REFCURSOR;
4 --
5 rw1 emp%ROWTYPE;
6 rw2 dept%ROWTYPE;
7 BEGIN
8 get_rows_count (rc1, rc2);
9
10 DBMS_OUTPUT.put_line ('Employees -----------');
11
12 LOOP
13 FETCH rc1 INTO rw1;
14
15 EXIT WHEN rc1%NOTFOUND;
16
17 DBMS_OUTPUT.put_line (rw1.ename);
18 END LOOP;
19
20 --
21 DBMS_OUTPUT.put_line ('Departments ---------');
22
23 LOOP
24 FETCH rc2 INTO rw2;
25
26 EXIT WHEN rc2%NOTFOUND;
27
28 DBMS_OUTPUT.put_line (rw2.dname);
29 END LOOP;
30
31 DBMS_OUTPUT.put_line ('First ref cursor: ' || rc1%ROWCOUNT);
32 DBMS_OUTPUT.put_line ('Second ref cursor: ' || rc2%ROWCOUNT);
33 END;
34 /
Result:
Employees -----------
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER
Departments ---------
ACCOUNTING
RESEARCH
SALES
OPERATIONS
First ref cursor: 14
Second ref cursor: 4
PL/SQL procedure successfully completed.
SQL>
You can use famous DBMS_OUTPUT.PUT_LINE() along with %ROWCOUNT suffix for your case such as
SET serveroutput ON
CREATE OR REPLACE PROCEDURE get_rows_count(
cursor1 OUT SYS_REFCURSOR,
cursor2 OUT SYS_REFCURSOR,
count1 OUT INT,
count2 OUT INT
) AS
cur_rec_obj user_objects%ROWTYPE;
cur_rec_seg user_segments%ROWTYPE;
BEGIN
OPEN cursor1 FOR SELECT * FROM user_objects;
LOOP
FETCH cursor1 INTO cur_rec_obj;
EXIT WHEN cursor1%NOTFOUND;
END LOOP;
OPEN cursor2 FOR SELECT * FROM user_segments;
LOOP
FETCH cursor2 INTO cur_rec_seg;
EXIT WHEN cursor2%NOTFOUND;
END LOOP;
count1 := cursor1%ROWCOUNT;
count2 := cursor2%ROWCOUNT;
DBMS_OUTPUT.PUT_LINE(count1);
DBMS_OUTPUT.PUT_LINE(count2);
END;
/
and you can call as follows from the SQL Window of PL/SQL Developer :
DECLARE
v_cursor1 SYS_REFCURSOR;
v_cursor2 SYS_REFCURSOR;
v_count1 INT;
v_count2 INT;
BEGIN
get_rows_count(v_cursor1, v_cursor2, v_count1, v_count2 );
END;
/

Need to fetch the table details using stored procedure when we give table name as input

CREATE TABLE test_table
(
col1 NUMBER(10),
col2 NUMBER(10)
);
INSERT INTO test_table
VALUES (1, 2);
I am writing a stored procedure wherein if I give a table name as an input, that should give me the table data and column details.
For example:
SELECT *
FROM <input_table_name>;
But this causes an error that the SQL command has not ended properly even though I have taken care of this.
My attempt:
CREATE OR REPLACE PROCEDURE sp_test(iv_table_name IN VARCHAR2,
p_out_cur OUT SYS_REFCURSOR)
AS
lv_str VARCHAR2(400);
lv_count NUMBER(1);
lv_table_name VARCHAR2(255):=UPPER(iv_table_name);
BEGIN
lv_str := 'SELECT * FROM '||lv_table_name;
SELECT COUNT(1) INTO lv_count FROM all_tables WHERE table_name = lv_table_name;
IF lv_count = 0 THEN
dbms_output.put_line('Table does not exist');
ELSE
OPEN p_out_cur FOR lv_str;
END IF;
END sp_test;
Tool used: SQL developer(18c)
In dynamic SQL, you do NOT terminate statement with a semicolon.
EXECUTE IMMEDIATE 'SELECT * FROM '||lv_table_name||';';
-----
remove this
Anyway, you won't get any result when you run that piece of code. If you really want to see table's contents, you'll have to switch to something else, e.g. create a function that returns ref cursor.
Sample data:
SQL> SELECT * FROM test_table;
COL1 COL2
---------- ----------
1 2
3 4
Procedure you wrote is now correct:
SQL> CREATE OR REPLACE PROCEDURE sp_test (iv_table_name IN VARCHAR2,
2 p_out_cur OUT SYS_REFCURSOR)
3 AS
4 lv_str VARCHAR2 (400);
5 lv_count NUMBER (1);
6 lv_table_name VARCHAR2 (255) := UPPER (iv_table_name);
7 BEGIN
8 lv_str := 'SELECT * FROM ' || lv_table_name;
9
10 SELECT COUNT (1)
11 INTO lv_count
12 FROM all_tables
13 WHERE table_name = lv_table_name;
14
15 IF lv_count = 0
16 THEN
17 DBMS_OUTPUT.put_line ('Table does not exist');
18 ELSE
19 OPEN p_out_cur FOR lv_str;
20 END IF;
21 END sp_test;
22 /
Procedure created.
Testing:
SQL> SET SERVEROUTPUT ON
SQL> DECLARE
2 l_rc SYS_REFCURSOR;
3 l_col1 NUMBER (10);
4 l_col2 NUMBER (10);
5 BEGIN
6 sp_test ('TEST_TABLE', l_rc);
7
8 LOOP
9 FETCH l_rc INTO l_col1, l_col2;
10
11 EXIT WHEN l_rc%NOTFOUND;
12
13 DBMS_OUTPUT.put_line (l_col1 || ', ' || l_col2);
14 END LOOP;
15 END;
16 /
1, 2 --> contents of the
3, 4 --> TEST_TABLE
PL/SQL procedure successfully completed.
SQL>
A function (instead of a procedure with the OUT parameter):
SQL> CREATE OR REPLACE FUNCTION sf_test (iv_table_name IN VARCHAR2)
2 RETURN SYS_REFCURSOR
3 AS
4 lv_str VARCHAR2 (400);
5 lv_count NUMBER (1);
6 lv_table_name VARCHAR2 (255) := UPPER (iv_table_name);
7 l_rc SYS_REFCURSOR;
8 BEGIN
9 lv_str := 'SELECT * FROM ' || lv_table_name;
10
11 SELECT COUNT (1)
12 INTO lv_count
13 FROM all_tables
14 WHERE table_name = lv_table_name;
15
16 IF lv_count = 0
17 THEN
18 raise_application_error (-20000, 'Table does not exist');
19 ELSE
20 OPEN l_rc FOR lv_str;
21 END IF;
22
23 RETURN l_rc;
24 END sf_test;
25 /
Function created.
Testing:
SQL> SELECT sf_test ('liksajfla') FROM DUAL;
SELECT sf_test ('liksajfla') FROM DUAL
*
ERROR at line 1:
ORA-20000: Table does not exist
ORA-06512: at "SCOTT.SF_TEST", line 18
SQL> SELECT sf_test ('TEST_TABLE') FROM DUAL;
SF_TEST('TEST_TABLE'
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
COL1 COL2
---------- ----------
1 2
3 4
SQL>

How to call and save the result set of oracle stored procedure which returns ref cursor in a procedure

I am trying to call a existing procedure in my new procedure:
Retrievedata returns a OUT sys_refcursor
I am trying to save the output result of Retrievedata procedure.
TYPE Doc IS REF CURSOR;
Doc := PKG_search.Retrievedata(IN_Id);
I am getting the following error:
PLS-00321: expression 'DOC' is inappropriate as the left hand side of an assignment statement
Thanks in Advance!
It wouldn't hurt if you posted some more info. My lucky guess is:
Function that returns refcursor (if you do have a procedure, it has to have an OUT parameter, but - that's not what code you posted suggests):
SQL> create or replace function f_test (par_deptno in number)
2 return sys_refcursor
3 is
4 l_rc sys_refcursor;
5 begin
6 open l_rc for select ename, job
7 from emp
8 where deptno = par_deptno;
9 return l_rc;
10 end;
11 /
Function created.
Procedure which uses that function, gets refcursor and displays it contents:
SQL> create or replace procedure p_test (par_deptno in number)
2 is
3 l_rc sys_refcursor;
4 --
5 l_ename emp.ename%type;
6 l_job emp.job%type;
7 begin
8 l_rc := f_test(par_deptno);
9
10 loop
11 fetch l_rc into l_ename, l_job;
12 exit when l_rc%notfound;
13 dbms_output.put_line(l_ename ||' - '|| l_job);
14 end loop;
15 close l_rc;
16 end;
17 /
Procedure created.
Testing:
SQL> set serveroutput on
SQL> exec p_test(10);
CLARK - MANAGER
KING - PRESIDENT
MILLER - CLERK
PL/SQL procedure successfully completed.
SQL>
If it is a procedure with an OUT parameter, then:
SQL> create or replace procedure p_one (par_deptno in number, par_out out sys_refcursor)
2 is
3 begin
4 open par_out for select ename, job
5 from emp
6 where deptno = par_deptno;
7 end;
8 /
Procedure created.
SQL> create or replace procedure p_test (par_deptno in number)
2 is
3 l_rc sys_refcursor;
4 --
5 l_ename emp.ename%type;
6 l_job emp.job%type;
7 begin
8 p_one (par_deptno, l_rc);
9
10 loop
11 fetch l_rc into l_ename, l_job;
12 exit when l_rc%notfound;
13 dbms_output.put_line(l_ename ||' - '|| l_job);
14 end loop;
15 close l_rc;
16 end;
17 /
Procedure created.
SQL> set serveroutput on
SQL> exec p_test(10);
CLARK - MANAGER
KING - PRESIDENT
MILLER - CLERK
PL/SQL procedure successfully completed.
SQL>

What does :1 mean in dynamic sql

vsql='select ename into y from emp where empno=:1'
what does :1 mean here?
It is a placeholder for a parameter value you'll be using.
For example:
SQL> set serveroutput on
SQL> declare
2 l_empno number := 7902;
3 v_sql varchar2(200);
4 l_ename varchar2(20);
5 begin
6 v_sql := 'select ename from emp where empno = :1';
7 execute immediate v_sql into l_ename using l_empno; --> this
8 dbms_output.put_line(l_ename);
9 end;
10 /
FORD
PL/SQL procedure successfully completed.
SQL>

Oracle stored procedure error on select

I am getting
ORA-06550: line 2, column 1:
PLS-00306: wrong number or types of arguments in call to 'GET_EMP_RS'
ORA-06550: line 2, column 1:
PL/SQL: Statement ignored
Error while executing select command stored procedure in oracle. My Procedure is
CREATE OR REPLACE
PROCEDURE get_emp_rs (p_deptno IN emp.EMPNO%TYPE,
p_recordset OUT SYS_REFCURSOR) AS
BEGIN
OPEN p_recordset FOR
SELECT ENAME,
JOB,
MGR
FROM emp
WHERE EMPNO = p_deptno
ORDER BY ENAME;
END;
/
You are not calling the procedure properly.
In SQL*Plus, you could do it as:
SQL> CREATE OR REPLACE
2 PROCEDURE get_emp_rs(
3 p_deptno IN emp.DEPTNO%TYPE,
4 p_recordset OUT SYS_REFCURSOR)
5 AS
6 BEGIN
7 OPEN p_recordset FOR
8 SELECT ENAME, JOB, MGR
9 FROM emp
10 WHERE DEPTNO = p_deptno
11 ORDER BY ENAME;
12 END;
13 /
Procedure created.
SQL>
SQL> SHOW ERRORS
No errors.
SQL>
SQL> variable cur refcursor
SQL>
SQL> DECLARE
2 cur SYS_REFCURSOR;
3 BEGIN
4 get_emp_rs(10, :cur);
5 END;
6 /
PL/SQL procedure successfully completed.
SQL>
SQL> print cur;
ENAME JOB MGR
---------- --------- ----------
CLARK MANAGER 7839
KING PRESIDENT
MILLER CLERK 7782
SQL>
Or,
It can be referenced from PL/SQL as:
SQL> DECLARE
2 l_cursor SYS_REFCURSOR;
3 l_ename emp.ename%TYPE;
4 l_job emp.job%TYPE;
5 l_mgr emp.mgr%TYPE;
6 BEGIN
7 get_emp_rs (p_deptno => 10, p_recordset => l_cursor);
8 LOOP
9 FETCH l_cursor INTO l_ename, l_job, l_mgr;
10 EXIT
11 WHEN l_cursor%NOTFOUND;
12 DBMS_OUTPUT.PUT_LINE(l_ename || ' | ' || l_job || ' | ' || l_mgr);
13 END LOOP;
14 CLOSE l_cursor;
15 END;
16 /
CLARK | MANAGER | 7839
KING | PRESIDENT |
MILLER | CLERK | 7782
PL/SQL procedure successfully completed.
SQL>

Resources