How can I call a function inside a procedure in plsql - oracle

I want to call a function inside a procedure and get it's value so I can use within the procedure but I have no idea how to do that ??
Any ideas ??
My function is the following one , this function returns a collection of employees' ids whose salary out of the max or min salary , I want to use this value in a procedure to update the salaries of those employees to the minimum salary ??

create or replace procedure P
a_variable_name number;
begin
a_variable := a_function('a parameter');
end;
/

Here is the sample code that will help you calling a function from a procedure.
create or replace FUNCTION ADD_TEN(P_IN VARCHAR2) RETURN VARCHAR2
AS
L_RESULT VARCHAR2(4000);
BEGIN
L_RESULT:=P_IN+10;
RETURN L_RESULT;
END;
create or replace PROCEDURE CALL_FUNCTON(P_IN VARCHAR2)
AS
L_FINAL_RESULT VARCHAR2(4000);
BEGIN
L_FINAL_RESULT:=ADD_TEN(P_IN);
DBMS_OUTPUT.PUT_LINE(L_FINAL_RESULT);
-- USE L_FINAL_RESULT IN YOUR BUSINESS LOGIC
END;
EXECUTE CALL_FUNCTON(5);

declare
procedure my_proc;
function my_func return number is
begin
my_proc;
return 3;
end my_func;
procedure my_proc is
begin
dbms_output.put_line('22');
end my_proc;
begin
dbms_output.put_line(my_func);
end;

Related

Using collection inside dynamic sql

I am trying to pass dbms_sql.number_table from one procedure to another and then using it inside a dynamic plsql block. But the below code throws error as:
Error(6,17): PLS-00306: wrong number or types of arguments in call to '||'
create or replace
procedure proc1( v_in_table_name varchar2,
v_in_column_name varchar2,
v_in dbms_sql.number_table)
as
plsql_block varchar2(4000);
begin
plsql_block:='declare
begin
FORALL INDX IN 1 ..'||v_in.count||' SAVE EXCEPTIONS
UPDATE '||v_in_table_name||'
Set '||v_in_column_name||'=123 WHERE col2='||v_in||'(INDX)||;
end';
execute immediate plsql_block;
end proc1;
You should make two changes:
First(and its case of error) its when you concatinate string with collection.
If you want to send collection into pl/sql block you shoud use the param.
And second you should add ; in the end of dynamic pl\sql:
create or replace
procedure proc1(v_in dbms_sql.number_table)
as
plsql_block varchar2(4000);
begin
plsql_block:='declare
l_collect dbms_sql.number_table := :number_table ;
begin
FORALL INDX IN 1 ..'||v_in.count||' SAVE EXCEPTIONS
UPDATE table_name
Set col1=123 WHERE col2=l_collect(INDX);
end;';
execute immediate plsql_block using v_in;
end proc1;
But after all changes I would like to ask: Are you realy need to use dynamic pl\sql?
There is no need for using a dynamic block. Also i dont think it can work as well. You can use this way;
create or replace
procedure proc1(v_in dbms_sql.number_table)
as
plsql_block varchar2(4000);
l_collect dbms_sql.number_table;
begin
l_collect := v_in;
FORALL INDX IN 1 ..l_collect.count SAVE EXCEPTIONS
UPDATE table_name
Set col1=123
WHERE col2=l_collect(INDX);
commit;
end proc1;
Execution:
SQL> DECLARE
var DBMS_SQL.number_table;
BEGIN
var (1) := 1;
var (2) := 2;
var (3) := 3;
proc1 (var);
END;
/
PL/SQL procedure successfully completed.
EDIT: As per your edit the code becomes like:
create or replace procedure proc1 (v_in_table_name varchar2,
v_in_column_name varchar2,
v_in dbms_sql.number_table)
as
plsql_block varchar2 (4000);
begin
plsql_block := q'[ FORALL INDX IN 1 ..v_in.count SAVE EXCEPTIONS
UPDATE :table_name
Set :col1=123
WHERE col2=v_in(INDX)]';
execute immediate plsql_block using v_in_table_name, v_in_column_name;
commit;
end proc1;

Calling SP with sys_refcursor as out parameter inside another procedure

I have an SP
create or replace PROCEDURE ALTERNATE_NAME_LOOKUP
( P_NAME IN VARCHAR2,
P_TYPE IN VARCHAR2, retCursor OUT SYS_REFCURSOR
)
I didn't paste the rest of its body; The above procedure works fine on its own (with the body of course)
Now I want to call it from another stored procedure, and I want to traverse over the refcursor.
What I am doing is declaring an_last_cur SYS_REFCURSOR; and calling ALTERNATE_NAME_LOOKUP procedure as ALTERNATE_NAME_LOOKUP(p_req.LASTNAMEEXP,c_LAST, an_last_cur); It compiles.
but when I add following block -
ALTERNATE_NAME_LOOKUP('Roman Reigns','LAST',an_last_cur);
For alt in an_last_cur
Loop
DBMS_OUTPUT.PUT_LINE('ok');
end loop;
It gives compilation error -
PLS-00221: 'AN_LAST_CUR' is not a procedure or is undefined
What am I doing wrong?
create or replace procedure alternate_name_lookup
( p_name in varchar2, p_type in varchar2, retcursor out sys_refcursor )
as
begin
open retcursor for select * from user_objects ;
end;
set serveroutput on
declare
an_last_cur sys_refcursor;
type my_objects is table of user_objects%rowtype;
objects my_objects;
begin
alternate_name_lookup('Roman Reigns','LAST',an_last_cur);
fetch an_last_cur bulk collect into objects;
dbms_output.put_line(objects.count);
for indx in 1 .. objects.count
loop
dbms_output.put_line(objects(indx).object_name);
end loop;
close an_last_cur;
end;
Try this one. Hope this helps. I dont have workspace with me so pardon
syntax erro r if any.
CREATE OR REPLACE PROCEDURE test_ref_prc
( p_ref_out OUT sys_refcursor)
AS
BEGIN
OPEN p_ref_out FOR
SELECT LEVEL FROM DUAL CONNECT BY LEVEL < 10;
END;
CREATE OR REPLACE PROCEDURE test_ref2
AS
refc sys_refcursor;
num_ntt NUMBER_NTT;
BEGIN
test_ref_prc(refc);
FETCH refc BULK COLLECT INTO num_ntt;
FOR I IN num_ntt.FIRST..num_ntt.LAST LOOP
dbms_output.put_line(num_ntt(i));
END LOOP;
END;
exec test_ref2;

Display result of Stored Procedure

I creates a procedure using Toad Client that is
create or replace procedure getuid(eid_pro varchar2)is
l_value number;
begin
select uniqueid
into l_value
from enrollment
where eid=eid_pro;
end ;
When I execute it by Followings
begin
getuid('245698154');
end;
It executed successfully but result is not displayed in data grid.
Please help me in this
Turn the procedure into a function.
create or replace function getuid(eid_pro varchar2) return number is
l_value number;
begin
select uniqueid
into l_value
from enrollment
where eid = eid_pro;
return l_value;
end;
And then select the function.
select getuid('245698154') from dual;
In that case please use a function and then you can use it in a select statement which can show the result in the grid.
create or replace function getuid(eid_pro varchar2) return number is
l_value number;
begin
select uniqueid
into l_value
from enrollment
where eid=eid_pro;
return l_value;
end ;
select getuid('245698154') from dual;

Procedure to input number and output varchar2

I need to write a procedure to input let's say a rep_id and then output the rep_name that corresponds to the rep_id.
After that, I need to use another procedure to call the above procedure.
Here is what I have for the first procedure.
create or replace procedure p_inout
(v_rep_id in number)
As
v_first_name varchar2(20);
v_last_name varchar2(20);
begin
select first_name,last_name into v_first_name, v_last_name
from rep
where rep_id = v_rep_id;
dbms_output.put_line(v_first_name||' '||v_last_name);
end p_inout;
/
Execute p_inout(100);
And here is my procedure to call the above procedure
create or replace procedure p_call
is
v_first_name varchar2(20);
v_last_name varchar2(20);
begin
p_inout(100);
dbms_output.put_line(v_first_name||' '||v_last_name);
end p_call;
/
execute p_call
I was able to get the result but one guy told me that my call procedure should be like this
Create or replace procedure p_call
Is
V_name varchar2(20);
Begin
P_inout(100,v_name); --100 is a rep id
Dbms_output.Put_line(v_name);
End;
/
Execute p_call
Doesn't my procedure to call and his call procedure produce the same result?
CREATE TABLE minions (
rep_id DATE CONSTRAINT minions__rep_id__pk PRIMARY KEY,
rep_name NUMBER CONSTRAINT minions__rep_name__nn NOT NULL
CONSTRAINT minions__rep_name__u UNIQUE
)
/
CREATE OR REPLACE PROCEDURE myCatWasSick (
p_rep_id IN minions.rep_id%TYPE,
p_rep_name OUT minions.rep_name%TYPE
)
IS
BEGIN
SELECT rep_name
INTO p_rep_name
FROM minions
WHERE rep_id = p_rep_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
p_rep_name := NULL;
END myCatWasSick;
/
CREATE OR REPLACE PROCEDURE releaseTheBadgers
IS
the_badger NUMBER(10);
BEGIN
myCatWasSick( SYSDATE + 1, the_badger );
// Do something with the_badger.
END releaseTheBadgers;
/

PL/SQL - execute immediate in pipelined function

I want to execute dynamic query in my pipelined function and return results of this query.
Is it possible to do this?
Pipelined function is convenient for me to achieve good interface for my application cause it behaves like a table.
The function:
CREATE OR REPLACE FUNCTION MyFunction(p_schema VARCHAR2) RETURN MyTableType Pipelined IS
v_query VARCHAR2(1000);
BEGIN
v_query := 'SELECT * FROM TABLE ('||p_schema||'.somepackage.SomeFunction)'; --SomeFunction is another pipelined function
EXECUTE IMMEDIATE v_query;
--Results of the v_query are compatible with MyTableType's row type. But how to return them from pipelined function?
END;
It is possible to combine dynamic SQL and pipelined function but the return type will not be dynamic: the number and type of columns returned will be fixed.
You can use EXECUTE IMMEDIATE with BULK COLLECT (thanks #be here now), dynamic cursors or DBMS_SQL to return more than one row. Here's an example with a dynamic cursor:
SQL> CREATE OR REPLACE PACKAGE pkg AS
2 TYPE test_tab IS TABLE OF test%ROWTYPE;
3 FUNCTION dynamic_cursor(l_where VARCHAR2) RETURN test_tab PIPELINED;
4 END;
5 /
Package created.
SQL> CREATE OR REPLACE PACKAGE BODY pkg IS
2 FUNCTION dynamic_cursor(l_where VARCHAR2) RETURN test_tab PIPELINED IS
3 cc sys_refcursor;
4 l_row test%ROWTYPE;
5 BEGIN
6 OPEN cc FOR 'SELECT * FROM test WHERE ' || l_where;
7 LOOP
8 FETCH cc INTO l_row;
9 EXIT WHEN cc%NOTFOUND;
10 PIPE ROW (l_row);
11 END LOOP;
12 RETURN;
13 END;
14 END;
15 /
Package body created.
Let's call this dynamic function:
SQL> SELECT *
2 FROM TABLE(pkg.dynamic_cursor('id <= 2'));
ID DAT
---------- ---
1 xxx
2 xxx
As always with dynamic SQL, beware of SQL Injection.
I think something like this:
CREATE OR REPLACE FUNCTION MyFunction(par1 VARCHAR2, ...) RETURN MyTableType Pipelined IS
v_query VARCHAR2(1000);
l_result MyTableType;
BEGIN
v_query := --My query created based on parameters
EXECUTE IMMEDIATE v_query into l_result;
pipe row(l_result);
END;
Works only if v_query returns 1 row.
I couldn't get #VincentMalgrat's answer to work. But it was very close. Definitely a big help in the right direction for me.
Here's what I got to work:
Package
CREATE OR REPLACE PACKAGE pkg AS
TYPE test_row IS RECORD ( test_name VARCHAR2 (255), test_number number, test_date date );
TYPE test_tab IS TABLE OF test_row;
FUNCTION dynamic_cursor(l_where VARCHAR2) RETURN test_tab PIPELINED;
END;
Package Body
CREATE OR REPLACE PACKAGE BODY pkg IS
FUNCTION dynamic_cursor(l_where VARCHAR2) RETURN test_tab PIPELINED IS
cc sys_refcursor;
l_row test_row;
BEGIN
OPEN cc FOR 'select name_column, number_column, date_column FROM my_table where number_column ='||l_where;
LOOP
FETCH cc INTO l_row;
EXIT WHEN cc%NOTFOUND;
PIPE ROW (l_row);
END LOOP;
RETURN;
END;
END;

Resources