Anonymous PL/SQL Block to call a procedure with collection - sql

I need to test a package procedure which accepts a PL/SQL table and returns SYS_REFCURSOR.
What I am looking for is Anonymous PL/SQL block which does the following :
populates PL/SQL table and pass to procedure
The relevant code is below:
create or replace type rec_typ as object
(
fname varchar2(10),
lname varchar2(10)
)
/
create or replace type rec_arr as table of rec_typ
/
create or replace package get_emp_pkg
as
procedure get_emp
(
l_rec rec_arr,
p_out out sys_refcursor
);
end;
/
create or replace package body get_emp_pkg
as
procedure get_emp
(
l_rec rec_arr,
p_out out sys_refcursor
)
as
l_out rec_arr;
begin
open p_out for select * from table ( l_out );
end;
end;
/

You need to declare and populate a table collection, and declare a cursor variable; and then pass those into the procedure call; e.g.:
declare
l_rec rec_arr;
l_cur sys_refcursor;
begin
l_rec := rec_arr(rec_typ('Joe','Bloggs'), rec_typ('Mary','Berry'));
get_emp_pkg.get_emp(l_rec, l_cur);
-- do something with the cursor
close l_cur;
end;
/
If you are just testing it and you're using SQL*Plus or SQL Developer you could simplify this to use a client bind variable:
variable cur refcursor;
declare
l_rec rec_arr;
begin
l_rec := rec_arr(rec_typ('Joe','Bloggs'), rec_typ('Mary','Berry'));
get_emp_pkg.get_emp(l_rec, :cur);
end;
/
print cur;
or even more simply:
variable cur refcursor;
begin
get_emp_pkg.get_emp(rec_arr(rec_typ('Joe','Bloggs'), rec_typ('Mary','Berry')), :cur);
end;
/
print cur;
and you could even replace that with an execute call, which is just a wrapper for an anonymous block anyway, so functionally almost identical.
Your procedure has a mistake though; you're declaring a local l_out variable and then opening the ref cursor based on that, but you don't ever populate it - so the ref cursor result set will always be empty. If you change it to use l_rec instead (though I would call that p_rec, with the p_ prefix indicating a parameters and leave the l_ prefix for local variables):
create or replace package body get_emp_pkg
as
procedure get_emp
(
l_rec rec_arr,
p_out out sys_refcursor
)
as
begin
open p_out for select * from table ( l_rec );
end get_emp;
end;
/
then the bind variable versions above both see:
PL/SQL procedure successfully completed.
FNAME LNAME
---------- ----------
Joe Bloggs
Mary Berry

Related

Dynamic SQL table name as variable

I have this procedure which is working, 2 parameters can be passed when calling procedure and it executes the select query.
create or replace procedure dynamic_sql
(input1 varchar2, input2 varchar2)
as begin
execute immediate
'select :variable1, :variable2 from emp'
using input1,input2;
end;
/
exec dynamic_sql('ename','job');
In the same way I try to add third variable which will replace the table Emp, but it doesn't work, passed in table name is 100% correct. This is the code that doesn't work (ORA-00903: invalid table name):
create or replace procedure dynamic_sql
(input1 varchar2, input2 varchar2,input_table varchar2)
as begin
execute immediate
'select :variable1, :variable2 from :variable3'
using input1,input2,input_table;
end;
/
exec dynamic_sql('ename','job','emp');
Try something like this:
Its due to the parsing of the table name before execution.
create or replace procedure dynamic_sql
(input1 varchar2, input2 varchar2,input_table varchar2)
as
str varchar2(1000) := NUll;
begin
str := 'select '||input1||','|| input2 ||' from '||input_table;
execute immediate str;
end;
/
exec dynamic_sql('ename','job','emp');
Procedure created.
PL/SQL procedure successfully completed.

How to store result of a function which will return sysrefcursor?

Scenario: there is an procedure inside which we have a cursor.
I need to call a function which will take an input from that cursor value and will return SYS_REFCURSOR.
I need to store that result of function in a different variable/cursor & need to return this value from procedure as out parameter.
I am using Oracle 11g.
How can I proceed?
PFB My Approach:
create or replace procedure prc_test
(p_dept_id in number,
c_detail out sysrefcursor)--need to add extra out parameter
as
var1 varchar2(200) :=null;
begin
open c_detail for
select -1 from dual;
if p_dept_id is not null then
open c_detail for
select emp_no from emp
where dept_id=p_dept_id;
--i need to retrn value of 'get_emp_dtls' function as out parameter.
end if;
end procedure;
/
Function to be called
CREATE OR REPLACE FUNCTION get_emp_dtls
(p_emp_no IN EMP.EMP_NO%TYPE)
RETURN SYS_REFCURSOR
AS
o_cursor SYS_REFCURSOR;
BEGIN
OPEN o_cursor FOR
SELECT
ENAME,
JOB
FROM emp
WHERE EMP_NO = p_emp_no;
RETURN o_cursor;
-- exception part
END;
/
Here is your function that takes a varchar2 variable and returns A refcursor( weakly typed).
CREATE OR replace FUNCTION fn_return_cur(v IN VARCHAR2)
RETURN SYS_REFCURSOR
IS
c1 SYS_REFCURSOR;
BEGIN
OPEN c1 FOR
SELECT 'ABC'
FROM dual
WHERE 'col1' = v;
RETURN c1;
END;
/
Here is the procedure that has a cursor value passed as argument to function and the returned cursor passed as OUT argument.
CREATE OR replace PROCEDURE Pr_pass_out_cur(v_2 OUT SYS_REFCURSOR)
IS
func_arg VARCHAR2(3);
other_arg VARCHAR2(3);
CURSOR c_2 IS
SELECT 'ABC' col1,
'DEF' col2
FROM dual;
BEGIN
LOOP
FETCH c_2 INTO func_arg, other_arg;
EXIT WHEN c_2%NOTFOUND;
v_2 := Fn_return_cur(func_arg);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
/
Let me know your feedback.

Alternate of sys_refcursor

What is the alternate of sys_refcursor.
After 12c upgrade, the resultset of sys_refcursor is unrecognizable by mulesoft/tibco. Reading it as null
Use
TYPE cursor_type IS REF CURSOR;
or a strongly typed cursor:
CREATE PACKAGE SCHEMA_NAME.PACKAGE_NAME
AS
TYPE Table_Name_Cursor IS REF CURSOR RETURN SCHEMA_NAME.TABLE_NAME%ROWTYPE;
-- You said this does not work.
-- PROCEDURE get_Weakly_Typed_Cursor (
-- out_cursor OUT SYS_REFCURSOR
-- );
PROCEDURE get_Strongly_Typed_Cursor (
out_cursor OUT Table_Name_Cursor
);
END;
/
CREATE PACKAGE BODY SCHEMA_NAME.PACKAGE_NAME
AS
PROCEDURE get_Strongly_Typed_Cursor (
out_cursor OUT Table_Name_Cursor
)
AS
BEGIN
OPEN out_cursor FOR
SELECT * FROM SCHEMA_NAME.TABLE_NAME;
END;
END;
/
You can define your own ref cursor type:
TYPE my_ref_cursor_type is REF CURSOR;
v_cursor my_ref_cursor_type;
But it would only make sense to do that if using a very old version of Oracle that didn't have SYS_REFCURSOR!

How to pass values in anonymous block with plsql table parameter

Table abc has the following column
approved_ain
1
2
12
34
i have a procedure
create or replace procedure abc( p_admin varchar2,
p_approved_ain abc.approved_ain)--plsql table in parameter
begin
end;
now when i call this procedure in an anonymous block :-
declare
l_Admin varchar2(100);
l_approved_ain abc.approved_ain;
begin
abc(l_Admin ,l_approved_ain);
commit;
end;
How can i pass values of the approved_ain of plsql table to this anonymous block.? that is i want to test it by passing the values of abc table approved_ain column.......
Answer :
declare
l_Admin varchar2(100);
l_approved_ain abc.approved_ain;
begin
l_approved_ain(1) :=123;
l_approved_ain(2) :=4645;
abc(l_Admin ,l_approved_ain);
commit;
end;
Given the fact that you only want to test, what about just setting the values in the anonymous block:
declare
l_Admin varchar2(100) := 'string';
l_approved_ain abc.approved_ain := ???;
begin
abc(l_Admin ,l_approved_ain);
commit;
end;

Returning a cursor , calling a procedure from other procedure

I have 2 procedures in same package.
I wish to use QOT_LST_M_QOT_PRE in QOT_LST_M_SEC_EXC_PRE. In QOT_LST_M_SEC_EXC_PRE I wish to find the argument - x_qot_id, call QOT_LST_M_QOT_PRE with this argument and also return it instead of the statement. Can I do it? How.
I mean something like
PROCEDURE QOT_LST_M_SEC_EXC_PRE (
i_sec_id IN NUMBER,
i_exc_id IN NUMBER,
o_recordset OUT SYS_REFCURSOR ) IS x_qot_id NUMBER(10);
------------------------------
BEGIN
---------------------------------------------------------------
--call a function instead of writing query from this function
open o_recordset for QOT_LST_M_QOT_PRE(x_qot_id, o_recordset);
----------------------------------------------------------------
END QOT_LST_M_SEC_EXC_PRE;
PROCEDURE QOT_LST_M_QOT_PRE
(
i_qot_id IN NUMBER,
o_recordset OUT SYS_REFCURSOR
--------------------------------
);
Sure you can. You can declare out parameters of type SYS_REFCURSOR and use them in your procedures, here is an example:
CREATE OR REPLACE PROCEDURE QOT_LST_M_QOT_PRE (i_qot_id IN NUMBER, THE_CURSOR OUT SYS_REFCURSOR) --Declare a sys_refcursor to be an out parameter, so it can be used outside
AS
BEGIN
OPEN THE_CURSOR FOR SELECT * FROM THE_TABLE WHERE X=i_qot_id;--Open the cursor
END;
CREATE OR REPLACE PROCEDURE QOT_LST_M_SEC_EXC_PRE (i_sec_id IN NUMBER, i_exc_id IN NUMBER)
AS
x_qot_id NUMBER(10); --Test param
RESULT_CURSOR SYS_REFCURSOR;--The cursor that will hold the opened cursor in QOT_LST_M_QOT_PRE procedure
SOMEVARIABLE VARCHAR2(10);--Test variables to hold results of cursor
BEGIN
QOT_LST_M_QOT_PRE(1,RESULT_CURSOR);--Procedure will open RESULT_CURSOR
LOOP --Loop cursor
FETCH RESULT_CURSOR INTO SOMEVARIABLE;
EXIT WHEN RESULT_CURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('READ :'||SOMEVARIABLE);
END LOOP;
CLOSE RESULT_CURSOR;--Close the opened cursor
END;