Can we call procedure inside function in oracle PL/SQL? If not then why? - sql

In some places I heard that we cannot call procedure inside function in oracle PL/SQL. May I know why is it so?
Also why cant we call a procedure within a SELECT statement whereas we can call a function in the same SELECT statement.

Yes you can call a procedure from a function in Oracle PL/SQL.
You can't call a procedure from a SELECT statement because it doesn't return a value. A function can be called from a SELECT because it does:
select empno, calc_salary_function(empno) salary
from emp;
Calling a procedure from a SELECT makes no sense really:
select empno, fire_employee(empno) -- Will fail
from emp;
What would you expect to see in the second column of the results?

Procedure is not used to return a value. Procedures performs group of operations to achieve a task, where as function is used to return a value.
Procedure is executed as an operation, function can be used in the select statement derive a value

you can call procedure from function.
create table test(a varchar2(30));
create or replace procedure pro_insert_values
as
begin
insert into test values('anything');
end;
create or replace function fn_get_data
return number
as
begin
pro_insert_values;
return 1;
end;
sql>variable x number
exec :x:=fn_get_data

You can use below code to validate that procedure can be called from inside function.
create table country_name(id number, country varchar2(100));
insert all
into country_name values(1, 'INDIA')
into country_name values(2, 'UK')
SELECT * FROM DUAL;
/
CREATE OR REPLACE FUNCTION COUNTRY_FOUND_NOTFOUND(V_NAME VARCHAR2)
RETURN VARCHAR2
AS
V_COUNTRY VARCHAR2(100);
BEGIN
BEGIN
SELECT COUNTRY INTO V_COUNTRY FROM country_name WHERE COUNTRY = V_NAME;
RETURN 'FOUND';
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT_COUNTRY(V_NAME);
RETURN 'NOT FOUND';
END;
RETURN 'NOT FOUND';
END;
/
CREATE OR REPLACE PROCEDURE INSERT_COUNTRY(V_NAME IN VARCHAR2)
AS
V_ID NUMBER;
BEGIN
SELECT MAX(ID) INTO V_ID FROM COUNTRY_NAME;
INSERT INTO COUNTRY_NAME VALUES(V_ID+1, V_NAME);
END;
/
SET SERVEROUTPUT ON;
DECLARE
V_NAME VARCHAR2(100);
BEGIN
V_NAME := COUNTRY_FOUND_NOTFOUND('SPAIN');
DBMS_OUTPUT.PUT_LINE(V_NAME);
END;

Related

How can execute dynamic sql if it is varchar2

I have PL/SQL function which is dynamically creating select statement an return this statement as varchar.Because I need this statement work dynamically(each time return different column count/name).For example it can return this select
'select id,name,currency,note from tabel t where t.id in(1,2,3,4,5,6);'
And I have another function must use this select statement result.
But the second select statement return that this string and cannot execute this select statement.
How can make first function return result as sql ?
Provided the caller knows the structure of the result:
CREATE OR REPLACE PROCEDURE execute_query(query IN VARCHAR2)
TYPE cur_typ IS REF CURSOR;
c cur_typ;
ID NUMBER;
Name VARCHAR2(20);
Currency VARCHAR2(20);
Note VARCHAR2(200);
BEGIN
OPEN c FOR query;
LOOP
FETCH c INTO ID, Name, Currency, Note;
EXIT WHEN c%NOTFOUND;
....
END LOOP;
CLOSE c;
END;
/
Use
EXECUTE IMMEDIATE Statement
as said in documentation:
https://docs.oracle.com/cd/B13789_01/appdev.101/b10807/13_elems017.htm

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.

stored PL/sql function using select statement

Example i have a stored pl/sql
CREATE OR REPLACE PROCEDURE number( test in NUMBER )
........
// rest of code
isn't possible that i don't want run this execute
execute number(2);
i want run with
select * from number(2);
isn't possible to run stored pl/sql script with select statement to call the function instead of execute?
You can't execute a PROCEDURE from SQL; however, you can execute a FUNCTION from SQL.
First, redefine NUMBER as a FUNCTION:
CREATE OR REPLACE FUNCTION NUMBER(pTest IN NUMBER) RETURN NUMBER IS
someValue NUMBER := pTest * 100;
BEGIN
-- whatever
RETURN someValue;
END;
Then execute it from a SELECT statement as
SELECT NUMBER(2) FROM DUAL;
Share and enjoy.

Oracle Stored Procedure: Returning a Multiple Rows

In my stored procedure it needs to get inputs and return multiple rows to a front-end application.
However the stored Procedure produces an errors:
SQL Statement ignored
not enough values
How to resolve?
Object type
CREATE TYPE org_rspnsble_prsns_type
AS OBJECT (
"appId" varchar2,
"orgId" varchar2,
"domainId" varchar2,
"leadName" varchar2,
"personId" number
);
Table type
CREATE TYPE org_rspnsble_prsns_table
AS TABLE OF org_rspnsble_prsns_type;
Stored Procedure
CREATE OR REPLACE PROCEDURE GetNames( appIdInput IN varchar2, orgIdInput IN varchar2, p_arr OUT org_rspnsble_prsns_table )
AS
BEGIN
SELECT "appId", "orgId", "domainId", "leadName", "personId"
BULK COLLECT INTO p_arr
FROM (
select "appId", "orgId", "domainId", "leadName", "personId"
from tableA
UNION
select "appId", "orgId", "domainId", "leadName", "personId"
from tableB
)
WHERE "appId" = appIdInput
AND "orgId" = orgIdInput;
END;
I found a good way to do it from:
https://asktom.oracle.com/pls/apex/ASKTOM.download_file?p_file=6551171813078805685
create or replace package types
as
type cursorType is ref cursor;
end;
/
create or replace function sp_ListEmp return types.cursortype
as
l_cursor types.cursorType;
begin
open l_cursor for select ename, empno from emp order by ename;
return l_cursor;
end;
/
create or replace procedure getemps( p_cursor in out types.cursorType )
as
begin
open p_cursor for select ename, empno from emp order by ename;
end;
/
Thank you to all who answered.
Your SELECT select 5 columns into 1 variable. You have to either
A) create object in your select:
SELECT org_rspnsble_prsns_type("appId", "orgId", "domainId", "leadName", "personId")
BULK COLLECT INTO p_arr
...
or B) create the type as record:
CREATE TYPE org_rspnsble_prsns_type
AS RECORD (...

PLSQL SELECT INTO FROM parameter

I created a function that should return the max id from a table(parameter)
CREATE OR REPLACE FUNCTION getmaxid
(
P_TABLE IN VARCHAR2
)
RETURN NUMBER IS
v_maxId NUMBER(38);
BEGIN
SELECT MAX(id) INTO v_maxId FROM P_TABLE;
RETURN v_maxId;
END getmaxid
However, i keep getting the error message "ORA-00942: table or view does not exist" on this line:
SELECT MAX(id) INTO v_maxId FROM P_TABLE;
Like explained earlier, you need to use dynamic SQL to perform the operation. In this case, p_table is a variable. The solution to this is to build a string that will contain the SQL and dynamically execute it one you've build the query.
The example below uses, DUAL, but the table name is arbitrary.
Here is what you're looking for, take the function outside of the block, I left it like this so that you can test it..
DECLARE
FUNCTION getmaxid (p_table IN VARCHAR2)
RETURN NUMBER
IS
v_maxid NUMBER (38);
v_select VARCHAR2 (200);
cnt SYS_REFCURSOR;
BEGIN
v_select := 'SELECT COUNT(*) FROM ' || p_table;
DBMS_OUTPUT.put_line (v_select);
EXECUTE IMMEDIATE v_select INTO v_maxid;
RETURN v_maxid;
END getmaxid;
BEGIN
DBMS_OUTPUT.put_line (getmaxid ('DUAL'));
END;