Calling a persistent package variable - sql

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...

Related

PL/SQL package - calling a procedure within a package

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.

Pl SQL Oracle PLS-00103: Encountered the symbol "CREATE"

this code takes input for zipcode, city, and state and then inserts that into the table created Address. Prior to inserting data it will check if the zipcode is already in the table, if so calling procedure(error) to display an error code.
Im getting an error code pls-00103: encountered the symbol "CREATE" when trying to execute the code. Here is my code so far. Thanks for any help in advance.
drop table address;
create table address(zipcode NUMBER, city varchar2(30), state varchar2(20));
create or replace procedure error as
begin
dbms_output.put_line('Error Zip Code already found in table');
end error;
declare
zzip number;
ccity varchar2(30);
sstate varchar2(30);
create or replace procedure location(p_zipcode NUMBER,
p_city varchar2,
p_state varchar2) is
zip address.zipcode%type;
cit address.city%type;
st address.state%type;
begin
select count(*) from address into zip where zipcode = zip;
if any_rows_found then
error;
else
Insert into address values(zip, cit, st);
end if;
end location;
begin
select &zipcode into zzip from dual;
select &city into ccity from dual;
select &state into sstate from dual;
procedure location(zzip, ccity, sstate);
end;
/
I'm not sure what you're trying to do, but the following may be closer to what you had in mind:
drop table address;
create table address(zipcode NUMBER, city varchar2(30), state varchar2(20));
declare
zzip number;
ccity varchar2(30);
sstate varchar2(30);
procedure error is
begin
dbms_output.put_line('Error Zip Code already found in table');
end error;
procedure location(p_zipcode NUMBER, p_city varchar2, p_state varchar2) is
zip_count NUMBER;
begin
select count(*)
into zip_count
from address
where zipcode = p_zipcode;
if zip_count > 0 then
error;
else
Insert into address
(zipcode, city, state)
values
(p_zipcode, p_city, p_state);
end if;
end location;
begin
select &zipcode into zzip from dual;
select &city into ccity from dual;
select &state into sstate from dual;
location(zzip, ccity, sstate);
end;
/
Best of luck.
I dont know if I understand your problem correctly, but there are certain correction I'd like to address to answer your problem
First, if you are going to create a procedure/function, do it in a separate worksheet then compile it. Dont compile it together with other anonymous blocks because most of the time, if you dont end your other blocks with '/', errors will surely generate.
Second, your DECLARE statement is misplaced, if you are going to make an anonymous block, make sure DECLARE, BEGIN and END are in line, dont create a procedure/function inside an anonymous block.
Third, you are declaring variables in your procedures and using them but doesnt have an initial value, so it will just pass a null value to the DML statement in your procedure. just use the parameter directly.
Fourth, avoid creating a procedure that only contains dbms_output.put_line. Its silly.
Lastly, your anonymous block that should be calling your procedure, uses '&', please avoid using '&' inside pl/sql as '&' is a feature in SQL*Plus and doesnt have any meaning in PL/SQL, instead, you can use ':' as for binding variables. But you use '&' not in binding variables so you should remove that;
Try this:
drop table address;
/
create table address(zipcode NUMBER, city varchar2(30), state varchar2(20));
/
create or replace procedure location(p_zipcode NUMBER,
p_city varchar2,
p_state varchar2) is
zip address.zipcode%type;
begin
select count(*)
from address
into zip
where zipcode = p_zipcode
and city =p_city
and state = p_state;
if zip > 0 then
dbms_output.put_line('Error Zip Code already found in table');
else
Insert into address values(p_zipcode, p_city, p_state);
end if;
end location;
/
begin
location(:zzip, :ccity, :sstate);
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

PL/SQL Package and Package Body

I've created a function inside my package body that counts the number of current customers in the customer database and I've created a function that creates a customer. But I am unsure to what i need to put inside the package itself. Here is the code that is inside the package body.
FUNCTION count_customer
RETURN NUMBER is
total NUMBER;
BEGIN
SELECT COUNT(*) into total FROM customer;
RETURN (total);
END;
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;
And then later in the package body I have this to calculate the new count.
BEGIN
total_customers := count_customer();
END;
The problem I am having is what to put in the actual package. I've got the create customer working inside the package it is just the customer count im having problems with.
Any ideas anyone?
You need to declare any procedures or functions that you want to be accessible form outside the package. They are private by default, meaning that they can only be called within the same package.
To expose both of those functions:
CREATE PACKAGE my_package AS
FUNCTION count_customer
RETURN 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;
END my_package;
CREATE PACKAGE BODY ...
There is much more in the documentation.
From what you have, though, I suspect you don't really want count_customers() to be exposed; you want a separate public function that returns the current value of total_customers. Although that assumes that all inserts and deletions always go through the package, otherwise the count will get out of step.
Put declarative part of any function or procedure that you want to accessed from "outside" like:
FUNCTION count_customer RETURN NUMBER;

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;