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'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>
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.
In a stored procedure I am filtering out list of employees whose role is SUPER.ADMIN
In such a case I used like expression as below
Emp.Role_nm Like ''''||p_rolenm||''''
p_rolenm I have mentioned in stored procedure as VARCHAR2
When ever I pass a value to p_rolenm as SUPER.ADMIN it's throwing error as identifier SUPER.ADMIN is not declared.
How I can escape . (Dot) in PL/SQL statements?
Why do you use that many single quotes? You don't need any (at least, I think so):
Sample data:
SQL> create table test (id number, role varchar2(20));
Table created.
SQL> insert into test
2 select 1, 'CLERK' from dual union all
3 select 2, 'SUPER.ADMIN' from dual;
2 rows created.
SQL> select * from test;
ID ROLE
---------- --------------------
1 CLERK
2 SUPER.ADMIN
SQL> set serveroutput on;
Procedure (anonymous, though, but that doesn't matter):
SQL> declare
2 p_rolenm varchar2(20) := 'SUPER.ADMIN';
3 l_id number;
4 begin
5 select id into l_id
6 from test
7 where role = p_rolenm;
8
9 dbms_output.put_line('l_id = ' || l_id);
10 end;
11 /
l_id = 2
PL/SQL procedure successfully completed.
SQL>
If you need like, then
SQL> declare
2 p_rolenm varchar2(20) := 'PER.ADM'; --> I changed this ...
3 l_id number;
4 begin
5 select id into l_id
6 from test
7 where role like '%' || p_rolenm || '%'; --> ... and this
8
9 dbms_output.put_line('l_id = ' || l_id);
10 end;
11 /
l_id = 2
PL/SQL procedure successfully completed.
SQL>
If you used dynamic SQL, then
SQL> declare
2 p_rolenm varchar2(20) := 'PER.ADM';
3 l_id number;
4 l_str varchar2(200); --> new variable for execute immediate
5 begin
6 l_str := q'[select id from test where role like '%' || :a || '%']';
7 execute immediate l_str into l_id using p_rolenm;
8
9 dbms_output.put_line('l_id = ' || l_id);
10 end;
11 /
l_id = 2
PL/SQL procedure successfully completed.
SQL>
Shortly, I don't understand what you are doing. Try to follow my examples. If it still doesn't work, post your SQL*Plus session.
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>