So I have this function called cal_approv that calculates a quantity of supply, by selecting
the sum of ordered quantity, the "present" quantity, and the min quantity of a giving product(idart)...fecthing information into cursor then inserting it into a result table(resultat), when i try to run this code
accept idarticle prompt 'Donner lid article : '
declare
FUNCTION cal_approv(code_art article.idart%type)
RETURN number IS qte _app number;
qtot number;
qtestk number;
qtemin number;
begin
select sum(qte_com) into qtot from lig_com where idart=code_art;
select qtestk into qtestk from article where idart=code_art;
select qtemin into qtemin from article where idart=code_art;
if ((qtot/qtestk)>(2*qtemin)) then
qte_app := qtot-qtestk*1.5;
else
qte_app := qtot*1.2;
end if;
return qte_app;
end;
/
drop function cal_approv;
declare
cursor arts is select idart, desart,pu from article where qtestk <= qtemin;
ida number;
da number;
qa number;
pa number;
begin
open arts;
loop
fetch arts into ida, da, pa;
qa := cal_ap prov(&idarticle);
pa := pa*cal_approv(&idarticle);
exit when(arts%notfound);
insert into resultat values(ida,da, qa,pa);
end loop;
close arts;
end;
/
select * from resultat;
I get this error
PLS-00201: identifier 'CAL_APPROV' must be declared
any help is appreciated!
Here's what I get when I indent your first block of PL/SQL code:
declare
FUNCTION cal_approv(code_art article.idart%type)
RETURN number
IS
qte_app number;
qtot number;
qtestk number;
qtemin number;
begin
select sum(qte_com) into qtot from lig_com where idart=code_art;
select qtestk into qtestk from article where idart=code_art;
select qtemin into qtemin from article where idart=code_art;
if ((qtot/qtestk)>(2*qtemin)) then
qte_app := qtot-qtestk*1.5;
else
qte_app := qtot*1.2;
end if;
return qte_app;
end;
/
Note that the end in the second-last line ends the function, not the anonymous PL/SQL block. This will cause an error because Oracle is expecting something like the following:
declare
FUNCTION cal_approv(code_art article.idart%type)
RETURN number
IS
-- ...
begin
-- body of function omitted
end;
begin
-- do something with this function
end;
/
Also, to be clear, a function declared within a PL/SQL block, rather than with a CREATE OR REPLACE FUNCTION ... statement, exists only while that block is being executed. Once the block completes, the function no longer exists. So you can write the following block:
DECLARE
FUNCTION add_one(p_in IN NUMBER)
RETURN NUMBER IS
BEGIN
RETURN p_in + 1;
END;
BEGIN
dbms_output.put_line(TO_CHAR(add_one(4));
END;
/
This should write 5 to dbms_output, if that has been enabled.
On the other hand, this won't work:
DECLARE
FUNCTION add_one(p_in IN NUMBER)
RETURN NUMBER IS
BEGIN
RETURN p_in + 1;
END;
BEGIN
NULL;
END;
/
BEGIN
dbms_output.put_line(TO_CHAR(add_one(4));
END;
/
This doesn't work because the function add_one is no longer available when the first block completes. The second block will fail with an error because it cannot find the function add_one.
There is no point attempting to use DROP FUNCTION with your function. DROP FUNCTION can only drop stored functions, and because your function is declared within a PL/SQL block, it is not a stored function.
As I see it you have two alternatives:
declare the function as a stored function, using CREATE OR REPLACE FUNCTION ..., outside of any DECLARE block, or
move all of the code that uses the function into the same block that declares the function.
In the latter case, your code would look something like the following (abbreviated for clarity):
declare
FUNCTION cal_approv(code_art article.idart%type)
RETURN number
IS
-- ...
begin
-- ...
end;
cursor arts is select idart, desart,pu from article where qtestk <= qtemin;
ida number;
da number;
qa number;
pa number;
begin
open arts;
loop
-- ...
end loop;
close arts;
end;
/
Related
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.
I have a question that does not give me sleep.
How can I select one field and put in multiple variables in Oracle.
Example:
declare
v_num_1 number;
v_num_2 number;
v_num_3 number;
begin
select 123 into v_num_1, v_num_2, v_num_3
from dual;
end;
This code is obviously incorrect - I give an error about too many variables.
However, I wonder if it exist another way to put in one value into multiple variables?
I will be very grateful for help.
Just repeat the 123:
declare
v_num_1 number;
v_num_2 number;
v_num_3 number;
begin
select 123, 123, 123 into v_num_1, v_num_2, v_num_3
from dual;
end;
Or use simple assignment:
declare
v_num_1 number;
v_num_2 number;
v_num_3 number;
begin
v_num_1 := 123;
v_num_2 := 123;
v_num_3 := 123;
end;
I am calling a function pck_my_pack.f_my_func in my anonymous block , f_my_func returns a sys_refcursor.
I want the value of req_column from sys_refcursor to used as
IF req_column>0 THEN
do this and that
END IF;
Problem is sys_refcursor which is being returned by my_func does not select values from a specific table. it selects values from multiple tables and few locals variables which were calculated in my_func.
Please help me out to get the value from this sys_refcursor.
Here is what I am trying:
DECLARE
TYPE cu_income_detail is ref cursor;
income_det cu_income_detail;
BEGIN
income_det := pck_my_pack.f_my_func(2542586);
FOR CURRVAL IN income_det LOOP -- I have also tried CUR_VAL
IF CURRVAL.pcls_paid_as_income > 0 THEN
-- Logic yet to be implemented once get the value
dbms_output.put('PCLS paid');
dbms_output.put_line(CUR_VAL.pcls_paid_as_income);
END IF;
END LOOP;
END;
declare
src_cur sys_refcursor;
curid NUMBER;
v_jobtitle varchar2(35);
v_min_salary number;
begin
open src_cur for 'select job_id,job_title,min_salary,max_salary from jobs';
curid := DBMS_SQL.TO_CURSOR_NUMBER(src_cur);
dbms_sql.define_column(curid,2,v_jobtitle,35);
dbms_sql.define_column(curid,3,v_min_salary);
WHILE DBMS_SQL.FETCH_ROWS(curid) > 0 LOOP
DBMS_SQL.COLUMN_VALUE(curid, 2, v_jobtitle);
DBMS_SQL.COLUMN_VALUE(curid, 3, v_min_salary);
DBMS_OUTPUT.put_line('job_titile='||v_jobtitle||' ;min_salary='||v_min_salary);
END LOOP;
DBMS_SQL.CLOSE_CURSOR(curid);
end;
You have to know type and name of columns in your sys_refcursor.
And perform fetch into operation on it.
DECLARE
TYPE cu_income_detail is ref cursor;
income_det cu_income_detail;
BEGIN
income_det := pck_my_pack.f_my_func(2542586);
loop
fetch income_det into var_1, var_2 ... var_3;
-- Logic here
exit when income_det%notfound;
end loop;
END;
create procedure proc_insert_salary(salary_emp in NUMBER,
empid in NUMBER(10),
desig in varchar2(20))
begin
DECLARE
gr_sal,hr,da,pf number;
BEGIN
set hr:= salary_emp*(15/100);
set da:= salary_emp*(8/100);
set pf := salary_emp*(35/100);
set gr_sal := salary_emp+hr+da-pf;
insert into emp_salary_details values (empid,desig, salary_emp, gr_sal);
end;
call proc_insert_salary (45000,10100,'C.E.O.')
when I call this procedure it gives error its in invalid state.
While #Guneli's answer is adequate, there's really no reason for the second block in this case. The following would be equivalent (and slightly simpler).
CREATE OR REPLACE PROCEDURE proc_insert_salary (salary_emp IN NUMBER,
empid IN NUMBER,
desig IN VARCHAR2) AS
hr NUMBER := salary_emp * (15 / 100);
da NUMBER := salary_emp * (8 / 100);
pf NUMBER := salary_emp * (35 / 100);
gr_sal NUMBER := salary_emp + hr + da - pf;
BEGIN
INSERT INTO emp_salary_details
VALUES (empid,
desig,
salary_emp,
gr_sal);
END;
/
Also, you should not that if you're going to have any other SQL in the same script (such as the call) then you need to end the procedure definition with a slash (/). This tells Oracle that procedure is finished and that it should compile it. Really, it's a good practice to always include it after procedural code.
Well, try this instead:
CREATE OR REPLACE PROCEDURE proc_insert_salary(
salary_emp IN NUMBER,
empid IN NUMBER,
desig IN VARCHAR2)
AS
BEGIN
DECLARE
gr_sal NUMBER;
hr NUMBER;
da NUMBER;
pf NUMBER;
BEGIN
hr := salary_emp*(15/100);
da := salary_emp*(8/100);
pf := salary_emp*(35/100);
gr_sal := salary_emp+hr+da-pf;
INSERT INTO emp_salary_details VALUES (empid,desig, salary_emp, gr_sal);
END;
END;
The things to note are that:
1) You can not show the size for the parameters of subprograms in PL/SQL, so NUMBER(10) or VARCHAR2(20) are incorrect.
2)The one line declaration of variables is not supported in PL/SQL, so instead of gr_sal,hr,da,pf number; you should use
gr_sal NUMBER;
hr NUMBER;
da NUMBER;
pf NUMBER;
3)To assign a value to variable you should not use SET, the ':=' is enough.
4)Also you have missed the 'end' clause for your second 'begin'.
I'm using Oracle SQL developer, or Oracle SQL* Plus
In SQL Plus you can do this:
var x number
exec :x := myfunction();
Or you may be able to use SQL:
select myfunction() from dual;
The example above shows how to call a function from SQL*Plus. If you're calling a function from a PL/SQL procedure, see the example below.
DECLARE
x NUMBER;
BEGIN
x := myfunction();
END;
A more complex example that will return a value of 100 (10*10):
DECLARE
x NUMBER;
FUNCTION mysquare(in_y IN NUMBER) RETURN NUMBER IS
BEGIN
RETURN in_y * in_y;
END mysquare;
BEGIN
dbms_output.enable;
x := mysquare(10);
dbms_output.put_line(x);
END;