PL/SQL package - calling a procedure within a package - sql

I am a pl/sql beginner trying to understand how to call procedure within the same package. This is a sample package body with 2 procedures. First is for creating an employee and second is creating an employee card if the emp_id is not empty. Can you please advice me how to proceed in the if statement block down below?
Thanks a lot!
create or replace PACKAGE BODY sample_package
IS
PROCEDURE create_employee(
emp_id IN OUT VARCHAR2,
emp_name IN VARCHAR2,
emp_surname IN VARCHAR2)
IS
BEGIN
schema.package.procedure(
emp_id,
emp_name,
emp_surname
);
IF (emp_id != null) THEN
--how do I call procedure create_id_card
END IF;
END;
PROCEDURE create_id_card(
card_id IN OUT VARCHAR2,
card_name IN VARCHAR2)
IS
BEGIN
schema.package.procedure(
card_id,
card_name
);
END;
END sample_package;

You have to find a way of passing variables card_id and card_name in the procedure create_employee like the below
PROCEDURE create_employee(
emp_id IN OUT VARCHAR2,
emp_name IN VARCHAR2,
emp_surname IN VARCHAR2)
IS
l_card_id VARCHAR2(100);
l_card_name VARCHAR2(255);
BEGIN
schema.package.procedure(
emp_id,
emp_name,
emp_surname
);
l_card_name:=emp_name;
IF emp_id is not null THEN
create_id_card(l_card_id, l_card_name);
END IF;
END;

As simple as that:
IF (emp_id is not null) THEN
--how do I call procedure create_id_card
create_id_card(parameter1, parameter2);
END IF;
As both procedures are in the same package, you don't have to do anything (precede its name with package or owner names, if that's what you meant).
I don't know which parameters you're actually passing so I named them just parameter_x.

Related

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

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;

PLS-00201: identifier 'NO_EMPLOYEES' must be declared

Hi Please i need assistance as im stuggling with the following error:
PLS-00201: identifier 'NO_EMPLOYEES' must be declared
CREATE or replace PACKAGE police_employee_mgmt AS
no_employees NUMBER;
FUNCTION insert_employee
(emp_id NUMBER, emp_name VARCHAR2, emp_grade NUMBER, emp_password VARCHAR2, emp_username VARCHAR2)
RETURN NUMBER;
PROCEDURE delete_employee(emp_id NUMBER);
PROCEDURE change_employee_grade(emp_id NUMBER, emp_grade NUMBER);
END police_employee_mgmt;
then a function is created to give the variable a value:
CREATE OR REPLACE FUNCTION number_of_employees
RETURN NUMBER IS
total_employees NUMBER;
BEGIN
SELECT COUNT(*)
INTO total_employees
FROM pl_police_employee;
RETURN(total_employees);
END;
Then...
BEGIN
no_employees := number_of_employees();
END;
As the error states, you need to declare no_employees. I asume your last code block is outside the package where you did declare it. I think you can use anonymous declares as well:
DECLARE
num_employees NUMBER;
BEGIN
num_employees := number_of_employees();
...
END

Calling a persistent package variable

Ive created a package and a package body that run but I'm unsure of how i can test the value held in my persistent package variable.
Here is the package code, its fairly simple just a delete procedure and create function which are in the package body.
CREATE OR REPLACE PACKAGE customers AS
FUNCTION create_customer (Country VARCHAR2, First_Name VARCHAR2, Last_name VARCHAR2,
Birth_date VARCHAR2, Customer_Type VARCHAR2, Address VARCHAR2)
RETURN VARCHAR2;
PROCEDURE remove_customer (customer_id VARCHAR2);
FUNCTION count_customer RETURN NUMBER;
END customers;
And now here is the package body
create or replace package body customers AS
total_customers NUMBER;
FUNCTION CREATE_CUSTOMER(
Country IN VARCHAR2 ,First_Name IN VARCHAR2 ,Last_Name IN VARCHAR2 ,Birth_Date IN VARCHAR2 ,Customer_Type IN VARCHAR2 ,Address IN VARCHAR2
) return VARCHAR2 IS
new_customer_id VARCHAR2(8);
BEGIN
SELECT custid_seq.NEXTVAL
INTO new_customer_id
FROM DUAL;
INSERT INTO customer (Customer_id, Country, First_Name, Last_name, Birth_date, Customer_Type, Address)
VALUES (new_customer_id, Country, First_Name, Last_name, Birth_date, Customer_Type, Address);
total_customers := total_customers + 1;
RETURN (new_customer_id);
end;
PROCEDURE remove_customer (customer_id VARCHAR2) IS
BEGIN
DELETE FROM customer
WHERE customer.customer_id = remove_customer.customer_id;
total_customers := total_customers - 1;
END;
BEGIN
select count(*) into total_customers from customer;
END;
The total_customers is my persistent package variable and only local to this package I just want to know how i can test to see the value currently held in the variable.
Thanks for the help
In your package specification add:
function get_total_customers return number;
In your package body add:
function get_total_customers return number is
begin
return total_customers;
end get_total_customers;
Then from SQL you can select customers.get_total_customers from dual.
The alternative is to have the package variable defined in the specification rather than the body, but then it could be changed externally as well as read.
Either way, the value will only be meaningful within a session; if you set it in one session then that won't be visible in another session. Both can calculate it, but then if you call create_customer() in one session, the other will still report the old total.
Put your variable to package spec, test it. Then put it back into the body or leave it in the spec. Keep it simple...

Procedure to insert employees: PL/SQL statement ignored

I am trying to insert values into an Employees table using the following procedure. I'm getting errors. Can anyone please explain the problem to me? Error code: Line 29: SQL statement ignored.
CREATE OR REPLACE PROCEDURE insert_employee(
p_emp_id IN NUMBER,
p_emp_fname IN VARCHAR2,
p_emp_sname IN VARCHAR2,
p_emp_add1 IN VARCHAR2,
p_emp_add2 IN VARCHAR2,
p_emp_town IN VARCHAR2,
p_emp_county IN VARCHAR2,
p_emp_telno IN NUMBER,
p_emp_position IN VARCHAR2,
p_emp_manager IN VARCHAR2
) IS
v_county_id County.county_id%type;
v_position_id Positions.position_id%type;
v_manager_id Facilities.facilty_id%type;
BEGIN
SELECT county_id
INTO v_county_id
FROM County WHERE county_name = p_emp_county;
SELECT position_id
INTO v_position_id
FROM Positions WHERE position_name = p_emp_position;
SELECT facility_manager
INTO v_manager_id
FROM Facilities WHERE facility_name = p_emp_manager;
INSERT INTO Employees (emp_id, emp_fname, emp_sname, emp_add1, emp_add2, emp_town, emp_county, emp_telno, emp_position, emp_salary, emp_manager)
VALUES(p_emp_id, p_emp_fname, p_emp_sname, p_emp_add1, p_emp_add2, p_emp_town, v_county_id, p_emp_telno, v_position_id, p_emp_salary, v_manager_id);
END;
/
Remove the SELECTs - they are in invalid syntax, and don't do anything necessary here anyway. ALso remove the pointless error "handler" which does nothing more than hide the error:
CREATE OR REPLACE PROCEDURE insert_employee(
p_emp_id IN NUMBER,
p_emp_fname IN VARCHAR2,
p_emp_sname IN VARCHAR2,
p_emp_add1 IN VARCHAR2,
p_emp_add2 IN VARCHAR2,
p_emp_town IN VARCHAR2,
p_emp_county IN VARCHAR2,
p_emp_telno IN NUMBER,
p_emp_position IN VARCHAR2,
p_emp_manager IN VARCHAR2
) IS
BEGIN
INSERT INTO Employees (emp_id, emp_fname, emp_sname, emp_add1, emp_add2, emp_town, emp_county, emp_telno, emp_salary, emp_position, emp_manager)
VALUES(p_emp_id, p_emp_fname, p_emp_sname, p_emp_add1, p_emp_add2, p_emp_town, p_emp_county, p_emp_telno, p_emp_salary, p_emp_position, p_emp_manager);
END;
If your example has been oversimplified and you actually need the values you were selecting before (e.g. you insert those into Employees also) then you need to use "select into" syntax e.g.
...
) IS
v_county_id county.county_id%type;
v_xxx county.xxx%type;
BEGIN
SELECT county_id
INTO v_county_id
FROM County WHERE county_name = p_emp_county;
...
Your local variable declarations should have semicolons at the end of each line:
) IS
v_county_id County.county_id%type;
v_position_id Positions.position_id%type;
v_manager_id Facilities.facilty_id%type;
Do you need to select into a cursor or a variable?
E.g.
SELECT county_id into v_country
FROM County WHERE county_name = p_emp_county;
you should type ; after variable definition instead comma.
check column name
v_manager_id Facilities.facilty_id%type;
FROM Facilities WHERE facility_name = p_emp_manager;
create or replace procedure procOne(sid OUT number,sname OUT varchar,fee OUT number)
as
begin
insert into student values(sid,sname,fee);
end;

Calling a member procedure in Oracle 11g

Lets say i have:
create type address as object (
line1 varchar2(50),
city varchar2(50),
member procedure insert_address(line1 varchar2, city varchar2)
)
/
create table address_table of address;
create type body address as
member procedure insert_address(line1 varchar2, city varchar2) is
begin
insert into address_table values (line1, city);
commit;
end insert_address;
end;
/
How do i call insert_address?
By doing the following i get invalid number or types of arguments
begin
address.insert_address('123 my road','london');
end;
i can do this and it works, but seems like a bad idea:
declare
v_address address := new address(null,null);
begin
v_address.insert_address('123 my road','london');
end;
Thanks
Use static instead of member for your procedure:
static procedure insert_address(line1 varchar2, city varchar2)
Then you can call it on the object type instead of the instance:
address.insert_address('123 my road','london');
See Using PL/SQL Object Types for more information.
As you have built it (which is bizarrely), the procedure insert_address can only be called in the context of an object of type address, and must be called with parameters line1 and city, with values that have no connection with the object you called it "for". This is how I would build the table and code, and use it:
create table address_table (line1 varchar2(50), city varchar2(50));
create package address_pkg as
procedure insert_address(p_line1 varchar2, p_city varchar2);
end;
/
create package body address_pkg as
procedure insert_address(p_line1 varchar2, p_city varchar2) is
begin
insert into address_table (line1, city) values (p_line1, p_city);
end;
end;
/
exec address_pkg.insert_address ('123 my road', 'london');
With your funkier model, it seems that the insert_address procedure should insert "the address object itself" into the table. Something like:
create type address as object (
line1 varchar2(50),
city varchar2(50),
member procedure insert_address
)
/
create table address_table of address;
create type body address as
member procedure insert_address is
begin
insert into address_table values (line1, city);
commit;
end insert_address;
end;
/
Then the insert would be like:
declare
v_address address := new address('123 my road','london');
begin
v_address.insert_address;
end;