I have a problem with procedures in PL/SQL. I have a public procedure declared in a package and I want to call another procedure(private) inside the first one.
PROCEDURE show_notesforstudent (number_id IN number) as
...
DBMS_OUTPUT.PUT_LINE('The notes for the student with number_id X are: '|| Y);
DBMS_OUTPUT.PUT_LINE('here is the call for the private procedure');
erase_student(number_id);
END;
This code is a general example, my code is bigger and I can't put it all here. Here is only the main idea.
For this call I face this error: "Error(31,5): PLS-00313: 'erase_student' not declared in this scope".
The implementation of erase_student procedure is:
PROCEDURE erase_student(n_id students.number_id%type) AS
student_inexistent EXCEPTION;
PRAGMA EXCEPTION_INIT(student_inexistent, -20002);
counter integer;
BEGIN
SELECT COUNT(nmber_id) INTO counter FROM studens where number_id = n_id;
IF counter = 0 THEN
raise student_inexistent;
END IF;
DELETE FROM students WHERE number_id = n_id;
EXCEPTION
WHEN student_inexistent THEN
raise_application_error (-20002, 'Student with number_id' || n_id || ' doesn't exists in database');
END stergere_student;`
Lets simplify your code and make it syntactically correct:
CREATE OR REPLACE PACKAGE package_name
AS
PROCEDURE show_notesforstudent (number_id IN number);
END;
/
CREATE OR REPLACE PACKAGE BODY package_name
AS
PROCEDURE show_notesforstudent (number_id IN number)
AS
BEGIN
erase_student(number_id);
END;
PROCEDURE erase_student(n_id NUMBER) AS BEGIN NULL; END;
END;
/
However, it still won't compile as we get PLS-00313: 'ERASE_STUDENT' not declared in this scope. It can be fixed by re-organising the package to ensure that the private procedure is declared before it is called; like this:
CREATE OR REPLACE PACKAGE BODY package_name
AS
PROCEDURE erase_student(n_id NUMBER) AS BEGIN NULL; END; -- Header and body
PROCEDURE show_notesforstudent (number_id IN number)
AS
BEGIN
erase_student(number_id);
END;
END;
/
However, if you want to keep the order of the procedures in the package then you could just use a forward declaration to declare the header for the private procedure before it is called and declare the body afterwards; like this:
CREATE OR REPLACE PACKAGE BODY package_name
AS
PROCEDURE erase_student(n_id NUMBER); -- Header only
PROCEDURE show_notesforstudent (number_id IN number)
AS
BEGIN
erase_student(number_id);
END;
PROCEDURE erase_student(n_id NUMBER) AS BEGIN NULL; END; -- Header and body
END;
/
Related
In the package I have couple of procedure that set global variables, example below:
...
PROCEDURE setA (pp IN VARCHAR2)
IS BEGIN global_vName := pp; END;
PROCEDURE setB (qq IN VARCHAR2)
IS BEGIN global_vColor := qq; END;
FUNCTION getA RETURN VARCHAR2
IS BEGIN RETURN global_vName; END;
FUNCTION getB RETURN VARCHAR2
IS BEGIN RETURN global_vColor; END;
...
Now in the PL/SQL block I'm doing test if they are working correclty:
Begin
mypack.setA('NameA');
mypack.setB('ColorB');
End;
How to write a procedure that will check if global_vName and global_vColor are set up?
If they are null procedure should return exception. Please help.
Do you mean this?
FUNCTION getA RETURN VARCHAR2 IS
BEGIN
IF global_vName IS NULL THEN
RAISE NO_DATA_FOUND;
END IF;
RETURN global_vName;
END;
There is no possibility to execute some code after the end statement - you should write it explicitly if you need additional check. As I understand, you want be sure that global variables are always initialized, so you can use the package initialization:
create or replace package body mypack as
PROCEDURE setA (pp IN VARCHAR2)
IS BEGIN global_vName := pp; END;
PROCEDURE setB (qq IN VARCHAR2)
IS BEGIN global_vColor := qq; END;
FUNCTION getA RETURN VARCHAR2
IS BEGIN RETURN global_vName; END;
FUNCTION getB RETURN VARCHAR2
IS BEGIN RETURN global_vColor; END;
< here are your other functions and procedures >
begin
-- here is an initialization section
setA('NameA');
setB('ColorB');
end mypack;
The initialization section will be executed automatically by Oracle before the first user's call to package (function, procedure, cursor, variable, etc.). So you can be sure that your variables are always initialized.
I've been given the task of converting a stored procedure, with several CRUD operations, to a package with functions defined.
When I created the package in Oracle SQL Developer, I defined may functions:
FUNCTION func1 RETURN NUMBER;
FUNCTION func2 RETURN NUMBER;
etc...
I have corresponding code in the 'package body':
FUNCTION func1 RETURN NUMBER
IS
BEGIN
-- some CRUD operation
END;
RETURN 0;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('FUNCTION func1: error ' || ERR_NUM || ', Msg:' || ERR_MSG);
ROLLBACK;
END func1;
When I run them, I can choose which function to run from the list supplied. My question is what do I need to write or do to have all functions run in sequence with one command?
thanks
If you need to run some procedures in a given order, you need to build a procedure or an anonymous block that calls the procedures in the right order.
For example:
create or replace package aPackage is
procedure runAll;
end;
create or replace package body aPackage is
procedure proc1 is
begin
dbms_output.put_line('Procedure 1');
end proc1;
--
procedure proc2 is
begin
dbms_output.put_line('Procedure 2');
end proc2;
procedure runAll is
begin
proc1;
--
proc2;
--
end runAll;
end;
The call:
SQL> exec aPackage.runAll;
Procedure 1
Procedure 2
PL/SQL procedure successfully completed.
SQL>
I used procedures just to call them without need to assign the result to a variable, but the idea is the same for functions.
With functions:
create or replace package aPackageFun is
function runAll return number;
end;
create or replace package body aPackageFun is
function fun1 return number is
begin
dbms_output.put_line('Inside function 1');
return 1;
end fun1;
--
function fun2 return number is
begin
dbms_output.put_line('Inside function 2');
return 2;
end fun2;
function runAll return number is
vNum1 number;
vNum2 number;
begin
vNum1 := fun1();
--
vNum2 := fun2();
--
return vNum1 + vNum2;
end runAll;
end;
The call:
SQL> select aPackageFun.runAll() from dual;
APACKAGEFUN.RUNALL()
--------------------
3
Inside function 1
Inside function 2
SQL>
About your code, notice that you have a commit after a return: the commit will never be executed.
I have created a package xyz like follows :-
create or replace package xyz
is
procedure abc( v_frst_param in VARCHAR2 default 'Y')
IS
BEGIN
dbms_output.put_line(v_frst_param);
-- CALLING another function
update_table(p_frst_parm =>v_frst_param,
p_second_param =>'2');
END;
In the dbms_output.put_line the output is coming null when i am not passing any value while calling abc procedure.
if i have passed default and i am not passign any parameter shouldnt the value come as Y in the ouput
First of all, I think that package would be invalid, you are trying to add a body for your function in your package specification. However the whole idea is good and it should be working, if done right, for example, create a package:
create or replace package xyz is
procedure abc(v_frst_param in varchar2 default 'Y');
procedure abc(v_frst_param in varchar2 default 'Y', v_second_param in varchar2);
end xyz;
And a package body:
create or replace package body xyz is
procedure abc(v_frst_param in varchar2 default 'Y') is
begin
dbms_output.put_line(v_frst_param);
end;
procedure abc(v_frst_param in varchar2 default 'Y', v_second_param in varchar2) is
begin
dbms_output.put_line(v_frst_param || ' / ' || v_second_param);
end;
end xyz;
Then you may want to make the call of your procedure:
begin
xyz.abc;
xyz.abc(); -- This is the same thing as above
xyz.abc(v_second_param => 'Maybe');
end;
Please note that if you send anything as a parameter for v_first_parameter to that procedure, it will use the value you sent and not the default one.
Try this out
Mostly depends on how you are calling your procedure -ABC(); or ABC; or ABC(NULL); or ABC(''); and the way your parameters are declared.
Create or replace procedure ABC(v_frst_param IN VARCHAR2 Default 'Y')
AS
OUT_v_frst_param VARCHAR2(100);
BEGIN
OUT_v_frst_param := v_frst_param ;
dbms_output.put_line('The PROCEDURE OUTPUT is : ' || OUT_v_frst_param );
END;
--Procedure created.
BEGIN
ABC(); --calling procedure
END;
The PROCEDURE OUTPUT is : Y
Statement processed.
Now if you call your procedure like:
BEGIN
ABC; --calling procedure
END;
The PROCEDURE OUTPUT is : Y
Statement processed.
--passing `NULL`
BEGIN
ABC(NULL);
END;
The PROCEDURE OUTPUT is :
Statement processed.
-- Passing again ''
BEGIN
ABC('');
END;
The PROCEDURE OUTPUT is :
Statement processed.
--passing text
BEGIN
ABC('hello world');
END;
The PROCEDURE OUTPUT is : hello world
Statement processed.
create or replace package XXX_MWA_LOV_TEST AS
TYPE t_ref_csr IS REF CURSOR;
PROCEDURE XXX_USERS_LOV (p_user_name IN VARCHAR2,x_users OUT NOCOPY t_ref_csr);
end XXX_MWA_LOV_TEST;
How to run XXX_USERS_LOV procedure in SQL*Plus?
I tried this code but getting the syntax error:
SQL> EXECUTE XXX_MWA_LOV_TEST.XXX_USERS_LOV('%',:my_p_out);
Procedure body:
create or replace package body XXX_MWA_LOV_TEST AS
PROCEDURE XXX_USERS_LOV (x_users OUT NOCOPY t_ref_csr,p_user_name IN VARCHAR2) IS
BEGIN
OPEN x_users FOR select user_id,user_name,description
from fnd_user
where user_name like p_user_name;
DBMS_OUTPUT.PUT_LINE('TESTING DATA');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR IN USER LOV '|| SQLERRM);
END XXX_USERS_LOV;
end XXX_MWA_LOV_TEST;
First of all, the order of the parameters must be the same in the spec and in the package body.
You can call the ref cursor like this:
declare
v_cursor xxx_mwa_lov_test.t_ref_csr;
var1 the_type_you_need;
var2 the_type_you_need;
...
begin
xxx_mwa_lov_test.xxx_users_lov(v_cursor,'username...');
loop
fetch v_cursor into var1, var2...;
exit when v_cursor%notfound;
... do what you want with the vars...
end loop;
end;
/
Using a package, how can i pass a variable assign in a procedure to the parameter of another procedure?
I'm not sure if you are wondering about global variables or how OUT parameters work. An example of using a procedure's OUT parameter is below. More info on using IN and OUT can be found here
create or replace package TEST_PKG
IS
procedure test(p_input IN NUMBER, p_output OUT NUMBER)
IS
BEGIN
p_output := p_input * p_input;
END test ;
procedure testRun
IS
v_input NUMBER := 0;
v_output NUMBER;
BEGIN
test(v_input, v_output);
DBMS_OUTPUT.PUT_LINE('OUTPUT : ' || v_output );
END test ;
END xyz;
create or replace package xyz
IS
procedure test
IS
v_temp varchar2(20); --local variable
BEGIN
v_temp:=20; --assigning value to a variable
--if procedure is within the same package,as this example shows ,then call as below
test2(v_temp);
--if procedure is in another package say PQR then call as below,
--but the procedure should be declared in the specification of the package PQR
PQR.test2(v_temp);
--if procedure is not inside any package ,just a single procedure is there
--,then call as below
test2(v_temp);
END test ;
procedure test2(p_temp IN varchar2)
IS
BEGIN
--do you processing
END test2;
END xyz;
Hope this helps