I'm using oracle 11 XE & Application Express 4.0.2.00.09 and I have this function that I want to print it's cursor. I don't know how to read the return of this function when it's called.
CREATE OR REPLACE FUNCTION stuff
RETURN sys_refcursor IS
rf_cur sys_refcursor;
BEGIN
OPEN rf_cur FOR
SELECT ename
FROM emp
WHERE sal = (SELECT MAX(sal)
FROM emp);
RETURN rf_cur;
END;
A simple option is to just select it (as any other function), but I guess that's not what you want:
SQL> select stuff from dual;
STUFF
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
ENAME
----------
KING
Another option requires PL/SQL (I guess that is what you're looking for):
SQL> set serveroutput on
SQL> declare
2 l_rc sys_refcursor;
3 l_ename emp.ename%type;
4 begin
5 l_rc := stuff;
6 fetch l_rc into l_ename;
7 dbms_output.put_line(l_ename);
8 end;
9 /
KING
PL/SQL procedure successfully completed.
SQL>
Related
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;
/
Hello I'm a beginner at PL/SQL and some help would be appreciated.
So I have this procedure here and my goal is to have it so that when this procedure is executed that I can enter a 5 digit integer (a zipcode) and it will just select those values from the table and display just as if I've done a query like
SELECT * FROM customers WHERE customer_zipcode = "input zipcode".
create or replace PROCEDURE LIST_CUSTOMER_ZIPCODE(
p_zipcode IN customers.customer_zipcode%TYPE,
p_disp OUT SYS_REFCURSOR)
-- User input Variable, Display Variable
IS
BEGIN
OPEN p_disp for SELECT customer_first_name, customer_zipcode FROM customers
WHERE customer_zipcode=p_zipcode;
EXCEPTION
-- Input Sanitization
WHEN no_data_found THEN
dbms_output.put_line('-1');
END;
EXEC LIST_CUSTOMER_ZIPCODE(07080);
When I execute this command I just keep getting this error.
https://i.stack.imgur.com/nCI8T.png
If you are using SQL*Plus or SQL Developer then you can declare a bind variable and then call the procedure passing the variable and then print it:
SELECT * FROM customers WHERE customer_zipcode = "input zipcode".
create or replace PROCEDURE LIST_CUSTOMER_ZIPCODE(
p_zipcode IN customers.customer_zipcode%TYPE,
p_disp OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN p_disp FOR
SELECT customer_first_name, customer_zipcode
FROM customers
WHERE customer_zipcode = p_zipcode;
EXCEPTION
-- Input Sanitization
WHEN no_data_found THEN
dbms_output.put_line('-1');
END;
/
VARIABLE cur SYS_REFCURSOR;
EXEC LIST_CUSTOMER_ZIPCODE('07080', :cur);
PRINT cur;
However, your exception handling block is never going to be called as the cursor can return zero rows without raising that exception so the procedure could be simplified to:
create or replace PROCEDURE LIST_CUSTOMER_ZIPCODE(
p_zipcode IN customers.customer_zipcode%TYPE,
p_disp OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN p_disp FOR
SELECT customer_first_name, customer_zipcode
FROM customers
WHERE customer_zipcode = p_zipcode;
END;
/
You can't just execute such a procedure as it expects 2 parameters; one is IN, while another is OUT (ref cursor which contains result set).
I don't have your tables so I'll demonstrate it using Scott's sample schema by passing department number and returning list of employees working in that department.
Procedure:
SQL> set serveroutput on
SQL> create or replace procedure p_list
2 (p_deptno in dept.deptno%type,
3 p_disp out sys_refcursor
4 )
5 is
6 begin
7 open p_disp for select ename, job from emp
8 where deptno = p_deptno;
9 end;
10 /
Procedure created.
This is how you use it:
SQL> declare
2 l_list sys_refcursor;
3 l_ename emp.ename%type;
4 l_job emp.job%type;
5 begin
6 p_list(10, l_list); --> calling the procedure; use 2 parameters
7
8 loop
9 fetch l_list into l_ename, l_job;
10 exit when l_list%notfound;
11 dbms_output.put_line(l_ename ||' - '|| l_job);
12 end loop;
13 end;
14 /
CLARK - MANAGER
KING - PRESIDENT
MILLER - CLERK
PL/SQL procedure successfully completed.
SQL>
TRY EXEC LIST_CUSTOMER_ZIPCODE(:p_Zipcode);
If you put ':' before any string, It will become substitution string and you can type your input.
I have a function with three outputs and one input. But how do I use the value that comes from the outputs? I need to check the values coming out of the outputs. Can someone explain to me how I do it?
As Koen has already said, you don't want to use a function in this case - use a procedure instead. Here's an example: procedure accepts empno and returns their name and salary via OUT parameters.
SQL> create or replace procedure p_test (par_empno in number, par_ename out varchar2, par_sal out number)
2 is
3 begin
4 select ename, sal
5 into par_ename, par_sal
6 from emp
7 where empno = par_empno;
8 end;
9 /
Procedure created.
This is one employee; use its empno when calling the procedure:
SQL> select empno, ename, sal from emp where rownum = 1;
EMPNO ENAME SAL
---------- ---------- ----------
7369 SMITH 920
SQL> set serveroutput on
To call the procedure, declare local variables (because you have to put the result into something):
SQL> declare
2 l_ename emp.ename%type;
3 l_sal emp.sal%type;
4 begin
5 p_test(7369, l_ename, l_sal);
6 dbms_output.put_line(l_ename ||' earns ' || l_sal);
7 end;
8 /
SMITH earns 920
PL/SQL procedure successfully completed.
SQL>
If it must be a function, code changes slightly as function has to return a value anyway (not just via OUT parameters); I chose to return deptno value:
SQL> create or replace function f_test (par_empno in number, par_ename out varchar2, par_sal out number)
2 return varchar2
3 is
4 l_deptno emp.deptno%type;
5 begin
6 select ename, sal, deptno
7 into par_ename, par_sal, l_deptno
8 from emp
9 where empno = par_empno;
10
11 return l_deptno;
12 end;
13 /
Function created.
SQL> declare
2 l_ename emp.ename%type;
3 l_sal emp.sal%type;
4 l_deptno emp.deptno%type;
5 begin
6 l_deptno := f_test(7369, l_ename, l_sal);
7 dbms_output.put_line(l_ename ||' earns ' || l_sal || ' and works in department ' || l_deptno);
8 end;
9 /
SMITH earns 920 and works in department 20
PL/SQL procedure successfully completed.
SQL>
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>
I am trying to do a stored procedure in SQL Developer, which returns multiple records from a single table. But when I call the procedure, it returns the empty variables (taking into account that the table has records).
CREATE OR REPLACE PROCEDURE PURE_ENC_SELECCIONAR_INTERACCIONES(
startDate IN varchar2,
endDate IN varchar2,
o_interactionId OUT PURE_ENC_INTERACTION.INTERACTIONID%TYPE,
o_interactionDate OUT PURE_ENC_INTERACTION.INTERACTIONDATE%TYPE,
o_queueId OUT PURE_ENC_INTERACTION.QUEUEID%TYPE,
o_personId OUT PURE_ENC_INTERACTION.PERSONID%TYPE,
o_numSolicitud OUT PURE_ENC_INTERACTION.NUMSOLICITUD%TYPE,
o_customerDni OUT PURE_ENC_INTERACTION.CUSTOMERDNI%TYPE,
o_customerName OUT PURE_ENC_INTERACTION.CUSTOMERNAME%TYPE,
o_ani OUT PURE_ENC_INTERACTION.ANI%TYPE,
o_dnis OUT PURE_ENC_INTERACTION.DNIS%TYPE,
o_custom1 OUT PURE_ENC_INTERACTION.CUSTOM1%TYPE,
o_custom2 OUT PURE_ENC_INTERACTION.CUSTOM2%TYPE,
o_custom3 OUT PURE_ENC_INTERACTION.CUSTOM3%TYPE,
o_custom4 OUT PURE_ENC_INTERACTION.CUSTOM4%TYPE,
o_custom5 OUT PURE_ENC_INTERACTION.CUSTOM5%TYPE)
IS
BEGIN
FOR loop_int IN (
SELECT INTERACTIONID, INTERACTIONDATE, QUEUEID, PERSONID, NUMSOLICITUD, CUSTOMERDNI,
CUSTOMERNAME, ANI, DNIS, CUSTOM1, CUSTOM2, CUSTOM3, CUSTOM4, CUSTOM5
INTO o_interactionId, o_interactionDate, o_queueId, o_personId, o_numSolicitud,
o_customerDni, o_customerName, o_ani, o_dnis, o_custom1, o_custom2, o_custom3,
o_custom4, o_custom5
FROM PURE_ENC_INTERACTION )
--WHERE INTERACTIONDATE >= startDate AND INTERACTIONDATE < endDate )
LOOP
DBMS_OUTPUT.PUT_LINE('InteractionID: '|| o_interactionId);
END LOOP loop_int;
END;
I execute the procedure:
SET serveroutput ON
DECLARE
o_interactionId VARCHAR2(200);
o_interactionDate VARCHAR2(200);
o_queueId VARCHAR2(200);
o_personId VARCHAR2(200);
o_numSolicitud VARCHAR2(200);
o_customerDni VARCHAR2(200);
o_customerName VARCHAR2(200);
o_ani VARCHAR2(200);
o_dnis VARCHAR2(200);
o_custom1 VARCHAR2(200);
o_custom2 VARCHAR2(200);
o_custom3 VARCHAR2(200);
o_custom4 VARCHAR2(200);
o_custom5 VARCHAR2(200);
BEGIN
PURE_ENC_SELECCIONAR_INTERACCIONES(
'2019-10-20T12:30:03',
'2019-10-29T03:30:03',
o_interactionId,
o_interactionDate,
o_queueId,
o_personId,
o_numSolicitud,
o_customerDni,
o_customerName,
o_ani,
o_dnis,
o_custom1,
o_custom2,
o_custom3,
o_custom4,
o_custom5);
END;
When I run it, returns:
Procedimiento PL/SQL terminado correctamente.
InteractionID:
InteractionID:
InteractionID:
InteractionID:
InteractionID:
InteractionID:
InteractionID:
InteractionID:
InteractionID:
InteractionID:
InteractionID:
InteractionID:
InteractionID:
InteractionID:
InteractionID:
InteractionID:
When I run this sample:
SELECT INTERACTIONID, INTERACTIONDATE, QUEUEID , PERSONID , NUMSOLICITUD , CUSTOMERDNI , CUSTOMERNAME , ANI , DNIS , CUSTOM1,CUSTOM2 ,CUSTOM3 ,CUSTOM4 ,CUSTOM5
FROM PURE_ENC_INTERACTION;
It returns all the registers fine.
What could be the problem?
Well, you didn't post what you exactly have. How do I know? Because the procedure has syntax errors. You can't use cursor FOR loop like that; INTO is required for SELECT statements in PL/SQL, but not where you used it.
Simplified, on Scott's schema, this is what you did:
SQL> create or replace procedure p_test (par_deptno in number, par_ename out varchar2) is
2 begin
3 for cur_r in (select ename from emp into par_ename
4 where deptno = par_deptno)
5 loop
6 dbms_output.put_line('Ename: ' || par_ename);
7 end loop;
8 end;
9 /
Warning: Procedure created with compilation errors.
SQL> show err
Errors for PROCEDURE P_TEST:
LINE/COL ERROR
-------- -----------------------------------------------------------------
3/17 PL/SQL: SQL Statement ignored
3/39 PL/SQL: ORA-00933: SQL command not properly ended
SQL>
As I said: your code is invalid.
This, on the other hand, is valid:
SQL> create or replace procedure p_test (par_deptno in number, par_ename out varchar2) is
2 begin
3 for cur_r in (select ename from emp
4 where deptno = par_deptno)
5 loop
6 par_ename := cur_r.ename;
7 dbms_output.put_line('Ename from P_TEST: ' || par_ename);
8 end loop;
9 end;
10 /
Procedure created.
SQL> declare
2 l_ename varchar2(20);
3 begin
4 p_test (10, l_ename);
5 dbms_output.put_line('Ename from anonymous PL/SQL block: ' || l_ename);
6 end;
7 /
Ename from P_TEST: CLARK
Ename from P_TEST: KING
Ename from P_TEST: MILLER
Ename from anonymous PL/SQL block: MILLER
PL/SQL procedure successfully completed.
SQL>
But, it is wrong (logically). The procedure fetched all employees (Clark, King, Miller), but the caller (i.e. the anonymous PL/SQL block) got only one value: the last one fetched by the cursor.
I doubt that this is what you want; doesn't make sense.
I don't know what you really want; perhaps it is to return all rows that satisfy certain condition. If that's the case, you can't return scalar values, that should be *something
else*. Ref cursor is one option, but - you don't need a procedure with bunch of parameters, then - maybe a function is a better option. For example:
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 from emp where deptno = par_deptno;
7 return l_rc;
8 end;
9 /
Function created.
SQL> select f_test(10) from dual;
F_TEST(10)
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
ENAME
----------
CLARK
KING
MILLER
SQL>