REF Cursor from Procedure PL/SQL - sql

I am trying to troubleshoot a PL/SQL package. I found a similar example to explain my question as I am new to learning PL/SQL and how a cursor works with a procedure.
So for example:
CREATE OR REPLACE PROCEDURE emp_by_job (
p_job VARCHAR2,
p_emp_refcur IN OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN p_emp_refcur FOR SELECT empno, ename FROM emp WHERE job = p_job;
END;
In this I see that p_job is defined as VARCHAR2. Then the SQL selects from EMP where job = p_job. All we've defined p_job as is VARCHAR2, not mapped to a field anywhere. How does the cursor know what to do with job = p_job, where does p_job's value come from?
Thank you!

A procedure doesn't do anything when it is compiled, it needs to be called/invoked. The value for p_job will be passed when the procedure is called. In the example below, emp_by_job is invoked from an anonymous pl/sql block with a value for the argument p_job of 'MANAGER'.
koen>CREATE OR REPLACE PROCEDURE emp_by_job (
2 p_job VARCHAR2,
3 p_emp_refcur IN OUT SYS_REFCURSOR
4 )
5 IS
6 BEGIN
7 OPEN p_emp_refcur FOR SELECT empno, ename FROM emp WHERE job = p_job;
8 END;
9* /
Procedure EMP_BY_JOB compiled
koen>set serveroutput on size 999999
koen>DECLARE
2 TYPE emp_t IS REF CURSOR;
3 l_emp emp_t;
4 l_emprow emp%ROWTYPE;
5 BEGIN
6 emp_by_job(p_job => 'MANAGER',p_emp_refcur => l_emp);
7 LOOP
8 FETCH
9 l_emp
10 INTO
11 l_emprow.empno,
12 l_emprow.ename;
13 EXIT
14 WHEN l_emp%notfound;
15 dbms_output.put_line(l_emprow.empno || ' ' || l_emprow.ename);
16 END LOOP;
17 END;
18* /
7698 BLAKE
7782 CLARK
7566 JONES
PL/SQL procedure successfully completed.
koen>

Related

How can I return a select-query that canges based on the parameters i use when calling a function?

I have been wrestling with this problem for a while now. I want to make a function that takes parameters. The function is supposed to, with user submitted parameters, change a select-statment and after return/run the select.
The function:
create or replace FUNCTION F_GET_TABLE(column1_in varchar2, column2_in varchar2)
return query
is
base_query constant varchar2(5000 char) :=
'select column1, column2 from CustomersTable;';
begin
replace(replace(base_query, 'column1', column2_in),'column2', column2_in );
queryToReturn query := base_query;
return queryToReturn;
end F_GET_TABLE;
In my head the end result should be that I call the function like this:
select F_GET_TABLE('f_name','e_mail') from dual;
And I should have the same result as if I wrote the select-statment as:
select f_name, e_mail from CustomersTable;
So I've tried in different ways to make the function return the query as I've described. However the best I managed to do was return a varchar2 with the select-statement - however then I have to remove "" from the start and end of the select-block and run it manually.. I couldn't seem to find any answers to my problem while searching the internet, please help me out here!
Here's how:
SQL> CREATE OR REPLACE FUNCTION f_get_table (column1_in VARCHAR2,
2 column2_in VARCHAR2)
3 RETURN VARCHAR2
4 IS
5 base_query VARCHAR2 (5000) := 'select column1, column2 from emp';
6 BEGIN
7 RETURN REPLACE (REPLACE (base_query, 'column1', column1_in),
8 'column2', column2_in);
9 END f_get_table;
10 /
Function created.
SQL> select f_get_table('ename', 'job') from dual;
F_GET_TABLE('ENAME','JOB')
--------------------------------------------------------------------------------
select ename, job from emp
SQL>
If you want to return result, then return ref cursor:
SQL> CREATE OR REPLACE FUNCTION f_get_table (column1_in VARCHAR2,
2 column2_in VARCHAR2)
3 RETURN SYS_REFCURSOR
4 IS
5 base_query VARCHAR2 (5000) := 'select column1, column2 from emp';
6 l_rc SYS_REFCURSOR;
7 BEGIN
8 OPEN l_rc FOR
9 REPLACE (REPLACE (base_query, 'column1', column1_in),
10 'column2',
11 column2_in);
12
13 RETURN l_rc;
14 END f_get_table;
15 /
Function created.
Testing:
SQL> SELECT f_get_table ('ename', 'job') FROM DUAL;
F_GET_TABLE('ENAME',
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
ENAME JOB
---------- ---------
KING PRESIDENT
BLAKE MANAGER
CLARK MANAGER
JONES MANAGE
<snip>

execute oracle stored proc which accepts 2 input arg and return 2 out

execute oracle stored proc which accepts 2 input arg and return 2 out
variable arg1refcursor
variable arg2refcursor
variable arg3 refcursor
variable arg4 refcursor
exec FOX_OWN.GET_FX_CUSIP('arg1', 'arg2', (sysdate+10), 'Y'), :arg1, :arg2, :arg3, :arg4)
print arg1
print arg2
print arg3
print arg4
???
create or replace
PROCEDURE
GET_RESULT(
in_arg1 IN VARCHAR,
in_arg2 IN VARCHAR,
IN_arg3 IN DATE,
out_arg1 OUT VARCHAR,
out_arg2 OUT VARCHAR,
out_arg3 OUT VARCHAR,
out_arg4 OUT NUMBER
)
as
....
...
END;
If you expect refcursor to be returned, then you shouldn't use VARCHAR2 (not VARCHAR!) as OUT datatype.
For example:
SQL> create or replace procedure get_result
2 (par_deptno in emp.deptno%type,
3 par_job in emp.job%type,
4 par_rc_emps out sys_refcursor,
5 par_rc_jobs out sys_refcursor
6 )
7 is
8 begin
9 open par_rc_emps for
10 select ename from emp
11 where deptno = par_deptno;
12
13 open par_rc_jobs for
14 select ename from emp
15 where job = par_job;
16 end;
17 /
Procedure created.
Let's try it:
SQL> var v_rc_emps refcursor
SQL> var v_rc_jobs refcursor
SQL> exec get_result(20, 'CLERK', :v_rc_emps, :v_rc_jobs);
PL/SQL procedure successfully completed.
SQL> print v_rc_emps
ENAME
----------
SMITH
JONES
SCOTT
ADAMS
FORD
SQL> print v_rc_jobs
ENAME
----------
SMITH
JAMES
MILLER
SQL>

Assign to variables values from rowtype parameter

I've searched on stackoverflow and other sources, but haven't found anything useful.
I have to implement a procedure that receives a row (hence "%rowtype") from Reservation table as a parameter.
The table's name is Reservation (as attributes: id_Reservation, id_Room, price, etc).
I created an anonymous block to create the var_reservation variable, which will serve as the parameter to the procedure:
CREATE OR REPLACE PROCEDURE priceCheckout(var_reservation reservation%ROWTYPE) IS
l_idReservation NUMBER;
l_idRoom NUMBER;
prie INT;
date1 DATE;
date2 DATE;
ex exception;
BEGIN
l_idReservation := var_reservation.id_reservation;
(...)
END;
But this is wrong. How can I correct this?
If you do it correctly, it works. Have a look at the following example based on Scott's DEPT table:
SQL> select * from dept;
DEPTNO DNAME LOC
---------- -------------------- --------------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL> set serveroutput on
Procedure:
SQL> create or replace procedure p_test (var_row dept%rowtype)
2 is
3 l_dname dept.dname%type;
4 begin
5 l_dname := var_row.dname;
6
7 dbms_output.put_line('Department name = ' || l_dname);
8 end;
9 /
Procedure created.
Testing:
SQL> declare
2 l_row dept%rowtype;
3 begin
4 select *
5 into l_row
6 from dept
7 where deptno = 10;
8
9 p_test(l_row);
10 end;
11 /
Department name = ACCOUNTING
PL/SQL procedure successfully completed.
SQL>
Saying that "this is wrong" is difficult to debug. It is not an Oracle error message so ... unless you specify what is "this" and, possibly, edit the question and post copy/paste of your own SQL*Plus session (like I did) so that we'd see what you did and how Oracle responded, YOYO.

How do I assign the value of a refcursor to a variable in PL/SQL

This stored procedure call returns a single varchar2 type value. The issue is that it comes back in a refcursor. I need to get the ID value and assign it to a variable instead of printing it to the console.
var r refcursor;
DECLARE
BEGIN
P_PACKAGE.INSERT_INVOICE(
IN_INVOICE_TYPE => L_INVOICE.INVOICE_TYPE,
OUTPUT => :R);
END;
/
print r;
Exactly as you said - you need to assign it to a variable. Here's an example based on Scott's schema.
SQL> create or replace procedure p_rc (par_deptno in number, par_rc out sys_refcursor)
2 is
3 begin
4 open par_rc for select ename, sal
5 from emp
6 where deptno = par_deptno;
7 end;
8 /
Procedure created.
Let's test it; pay attention to lines #4, 5 (declaration of variables) and #10 (fetch into those variables):
SQL> declare
2 l_rc sys_refcursor;
3 -- declare variables which will get values returned by refcursor
4 l_ename emp.ename%type;
5 l_sal emp.sal%type;
6 begin
7 p_rc(10, l_rc);
8
9 loop
10 fetch l_rc into l_ename, l_sal;
11 exit when l_rc%notfound;
12 dbms_output.put_line(rpad(l_ename, 10, ' ') ||': '|| l_sal);
13 end loop;
14 end;
15 /
CLARK : 2450
KING : 5001
MILLER : 1300
PL/SQL procedure successfully completed.
SQL>
I wouldn't define the REFCURSOR in SQL*Plus as you've shown it. Assuming that your REFCURSOR was opened with a statement similar to
SELECT ID
FROM SOME_TABLE
WHERE SOMEFIELD = some_value
then your PL/SQL code should look something like
DECLARE
aString VARCHAR2(2000);
rc SYS_REFCURSOR;
BEGIN
P_PACKAGE.INSERT_INVOICE(
IN_INVOICE_TYPE => L_INVOICE.INVOICE_TYPE,
OUTPUT => rc);
FETCH rc
INTO aString;
DBMS_OUTPUT.PUT_LINE('aString = ''' || aString || '''');
END;

returning a value using dbms_output.put_line and out parameter in an Oracle procedure

What is the difference between printing a value using dbms_output.put_line and out parameter in oracle procedure. Will dbms_output.put_line return value to front end?
If not, how to return more than one row to front end using a stored procedure?
DBMS_OUTPUT.PUT_LINE doesn't make much sense in stored procedures or front end applications that can't display it (for example, although it makes a valid call in Oracle Forms or Application Express, you won't see anything on the screen).
You don't really expect users to run your procedures in SQL*Plus or TOAD or SQL Developer, do you? Therefore, use DBMS_OUTPUT.PUT_LINE for debugging purposes.
I guess that this is what you might be using:
SQL> create or replace procedure p_test_2
2 (par_deptno in number)
3 is
4 begin
5 for cur_r in (select ename from emp where deptno = par_deptno) loop
6 dbms_output.put_line(cur_r.ename);
7 end loop;
8 end;
9 /
Procedure created.
SQL> exec p_test_2(10);
CLARK
KING
MILLER
PL/SQL procedure successfully completed.
SQL>
If you want to compare it to a procedure that is supposed to return multiple values, then one option is to use OUT parameter whose datatype is SYS_REFCURSOR. Here's how; you'll notice that it requires some more code - the procedure itself and separate PL/SQL block which will do something with its result.
SQL> create or replace procedure p_test3
2 (par_deptno in number, par_emp out sys_refcursor)
3 is
4 begin
5 open par_emp for select * from emp where deptno = par_deptno;
6 end;
7 /
Procedure created.
SQL>
SQL> declare
2 l_emp sys_refcursor;
3 l_rec emp%rowtype;
4 begin
5 p_test3(10, l_emp);
6
7 loop
8 fetch l_emp into l_rec;
9 exit when l_emp%notfound;
10 -- You'd do something with those values here; I'm just displaying ENAME
11 dbms_output.put_line(l_rec.ename);
12 end loop;
13 end;
14 /
CLARK
KING
MILLER
PL/SQL procedure successfully completed.
SQL>
Alternatively, for display purposes, in SQL*Plus you might use this:
SQL> var l_rec refcursor
SQL> exec p_test3(10, :l_rec);
PL/SQL procedure successfully completed.
SQL> print l_rec
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
7782 CLARK MANAGER 7839 09.06.1981 00:00:00 2450 10
7839 KING PRESIDENT 17.11.1981 00:00:00 5000 10
7934 MILLER CLERK 7782 23.01.1982 00:00:00 1300 10
SQL>
Your function uses DBMS_OUTPUT.PUT_LINE to display your results column-wise, followed by a new_line character. for example please refer below query.
create or replace procedure TEMP_ARRAy_RECORD
is
--type emp_det_tbl IS TABLE OF temp_employee_det%ROWTYPE index by pls_integer;
type lemp_det IS RECORD
(
--l_emp_id int,
l_emp_id temp_employee_det.emp_id%type,
l_city temp_employee_det.city%type,
l_amount temp_employee_det.amount%type
);
TYPE emp_det IS VARRAY(15) OF lemp_det;
f_emp_det emp_det;
BEGIN
for i in (select emp_id,city,amount BULK COLLECT into f_emp_det from temp_employee_det)
loop
dbms_output.put(i.city||',');--fetch all data in single row
dbms_output.put_line(i.city||',');--fetch all data in column wise
exit when SQL%NOTFOUND;
end loop;
dbms_output.new_line;--
end;
execute TEMP_ARRAy_RECORD
refer below output will be shown.
SQL*Plus statement executed
PL/SQL block executed
CHALISGAON,BHADGAON,PACHORA,JALGAON,NASHIK,
Depends on what you mean by "front end". If you're running in SQL*Plus or SQL Developer, using dbms_output will sent content to a buffer, that's then displayed in a particular window - if serveroutput is on for that session.
A properly instrumented program would use a utility such as Logger to make debugging notes to a custom table, for later perusal.
OUT parameters in procedures just receive that information into the actual parameter, perhaps some local variable. This could be further processed, displayed on screen, or sent to another procedure.
DBMS_OUTPUT does not return output in the sense of an I/O stream or function return value. It is a rather basic debugging tool, that works by placing the specified text into a PL/SQL array that can then be retrieved at the end of the call by the client application calling dbms_output.get_lines(). Tools such as SQL*Plus and PL/SQL Developer do this automatically, subject to preference settings, but a web front end will not.