Sie sind auf Seite 1von 51

INTRODUCTION TO RELATIONAL

DATABASE AND SQL


CARER DATABASE SCHEDULING SYSTEM

FINAL PROJECT DOCUMENT

Submitted by: Ademola Kazeem


Student No: 15200214

Due: 29th April, 2016

PART ONE

Project Idea
Carer Database Scheduling System is a project that allows Carer to specify their availability
for job scheduling. Each carer is assigned to clients based on the carers' availability by an
manager who is the manager of a Homecare Company. The carers can also schedule their
holidays and manager can either grant or deny the holiday for any holiday requests by any
carer. The manager can assign cover for a carer that is on holiday.
Business Rules

Carer is an employee of the company that takes care of the companys Clients.
Each Carer has manager and 1 manager can manage more than one Carers.
The Carer specifies his/her availability in the system, which in our case is a many-tomany relationship, so it was divided into 2 called Carer_Availability.
The Manager assigns Carer to different Clients by setting up a roster (called Visit in the
diagram)
A Carer can book many holidays in a year, based on the acceptance or rejection of the
Manager and number of holiday days the Carer is allowed by the Company.
The manager can either grant or deny holiday request by the Carer.
Once a Carer is on holiday, there is need for cover.
A Cover is also a Carer, except that he/she would be covering for someone on holiday.
A manager assigns visits, and a Carer can visit many Clients while 1 Clients can be
visited by many Carer.
A Carer can visit many times within a period.
A period is a range of days that a Carer is scheduled to visit some specific Clients, the
range of time could be 3 weeks range.
Clients have comments, apart from their names, address etc.
These Comments may include medication, personal care, Grooming/Dressing, Client
safety, house work, and other information needed by the Carer to take care of the
Client.

Entities in the Database


1. Manager(managerId, username, firstname, lastname, DateOfBirth, email, dateCreated,
dateUpdated)
2. Address(postcodes, street, city, county, country)
3. Carer(carerId, username, firstname, lastname, sex, phone, ppsNumber, adminNote,
userStatus, DateOfBirth, email, dateCreated, dateUpdated)
4. Company_Car(reg_number, model, assigned_to, assigned_date)
5. Client(clientId, firstname, lastname, sex, phone, DateOfBirth, commentId)
6. Comments(commentId, dressing, communication, housework, medication, safety,
nutrition)
7. Availability (availabilityId, dayOfTheWeek, time)
8. Period(periodId, fromdate, todate, fromtime, totime, duration)
9. Holiday(carerId,
managerId,
date,
numberOfDays,
numberOfDaysAllowed,
numberOfDaysTaken, status)

10. Visit (visitId, carerId, clientId, periodId, managerId)


11. Cover(carerId, coverCarerId, reason, visitId)
12. Carer_Availability (carerId, availabilityId)
13. Company_Car(reg_number, model, assigned_to_carerid, assigneddate)
14. Company_car_audit(reg_number,
model,
assigned_to_carerid,
recordeddate, operation)

assigneddate,

Functional Dependencies
1. Manager(managerId, username, firstname, lastname, DateOfBirth, securityLevel, email,
dateCreated, dateUpdated)
2. Carer(carerId, username, firstname, lastname, sex, address, county, phone,
ppsNumber, adminNote, userStatus, DateOfBirth, email, dateCreated, dateUpdated)

1 to Many Relationship
1 Manager Grants Many Holidays
1 Manager assigns many visits
1 Carer has many holidays
1 Period involves many visits
1 cover can make many visits

Many to Many Relationship


Many carers has many availabilities (Carer_availabilities)
Many carers visit many Clients

1 to 1 Relationship
1 carer may be assigned 1 Company_Car
1 Client has 1 Comment

PART TWO

Note: The whole project is exported using expdp and it is attached as part of the document,
more information is in the log file.

Database Setup

Proof of 3rd Normal Form


One of the example is demonstrated below:

Here, the 3rd normal form is demonstrated in the two tables above, with the use POSTCODES
as the foreign key in client table as well as carer table.
The POSTCODES column was made NOT NULL because we believe that all carer should have
address and all clients should have address that the carer will visit.
All other tables follow 3rd normal form too.
For instance, the table availability and table carer have many to many relationship that do not
split, so we have another table called carer_availability, that host the relationship between
the two tables, as shown in the ERDiagram above.

The tables are included in the sql document attached with this document.

Click on the logo to open the SQL file.

Select * from address;

Select * from company_car

Select * from carer

Select * from client

Comments is a table that contains more information about a client that a carer will go visit.
Select * from comments

Select * from manager

Period is the time by which the carer is being assigned for.

4 INNER JOIN queries with descriptions


INNER JOIN 1 Description: The first INNER JOIN was used in prc_view_all_cr_avail_assigned
procedure with cursor that allows us to view list of all the carers that have chosen availability
before they are being assigned to a client. The code is shown below:
procedure prc_view_all_cr_avail_assigned
is
CURSOR carer_avail_cursor IS
--list all the list of carers that have selected their availabilities for work
SELECT A.FIRSTNAME firstname, A.LASTNAME lastname, C.DAYOFTHEWEEK DAYOFTHEWEEK,
C.FROMTIME FROMTIME, C.TOTIME TOTIME FROM carer A INNER JOIN carer_availability B
ON A.CARERID = B.CARERID INNER JOIN availability C ON B.AVAILABILITYID =
C.AVAILABILITYID ORDER BY A.FIRSTNAME ASC;
selected_carer_avail_row carer_avail_cursor%ROWTYPE;
begin

OPEN carer_avail_cursor;
FETCH carer_avail_cursor INTO selected_carer_avail_row;
DBMS_OUTPUT.PUT_LINE('LIST OF CARERS AND THEIR AVAILABILITY');
DBMS_OUTPUT.PUT_LINE('');
DBMS_OUTPUT.PUT_LINE('FULLNAME' || CHR(9) || CHR(9) || CHR(9) || 'DAY OF THE
WEEK' || CHR(9)|| CHR(9) || 'FROM TIME' || CHR(9) || CHR(9) || 'TO TIME');
WHILE carer_avail_cursor%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(selected_carer_avail_row.firstname || ' ' ||
selected_carer_avail_row.lastname || CHR(9) || CHR(9) || CHR(9) ||
selected_carer_avail_row.dayoftheweek ||
CHR(9) || CHR(9) || CHR(9) || CHR(9) ||CHR(9) ||
selected_carer_avail_row.fromtime || CHR(9) || CHR(9) ||CHR(9) || CHR(9) ||
selected_carer_avail_row.totime);
FETCH carer_avail_cursor INTO selected_carer_avail_row;
END LOOP;
CLOSE carer_avail_cursor;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No data to display, sorry!');
WHEN others THEN
DBMS_OUTPUT.PUT_LINE('Error!');
PKG_MISC_FUNCTIONS.ORA_RAISERROR(sqlcode, 'Error Just occur with error code
'||sqlcode, 25);
end;

The screenshot showing the anonymous procedure that run the procedure.

We used the screenshot below to add assign new carer to availability

And the screenshot below shows the list of all the carers who has selected availability

INNER JOIN 2: We want to check the day of the week that a carer is available. i.e. if the
weekday (e.g. MONDAY) specified by the input date is one of the days that the carer
specified as his/her availability.
procedure prc_schedule_visit(var_carer_id number, client_id number, var_period_id
number,
var_manager_id number, var_date varchar2, var_from_time varchar2, var_to_time
varchar2)
as
add_result number;
var_v_count number;
var_p_count number;
var_count_mgr number;
var_from_date varchar2(50);
var_to_date varchar2(50);
var_to_in timestamp;
var_from_in timestamp;
var_given_day_of_week varchar2(15);
var_av_day_of_week NUMBER;
begin
var_from_date := var_date ||' ' || var_from_time;
var_to_date := var_date ||' ' || var_to_time;
var_from_in:= TO_DATE(var_from_date, 'MM/DD/YYYY HH24:MI');
var_to_in := TO_DATE(var_to_date, 'MM/DD/YYYY HH24:MI');
--check if the carer has been assigned to this client for this period and
this time before
--if yes show response if not, continue to the next line of action.
select count(1) into var_v_count from visit where periodid = var_period_id
and
carerid = var_carer_id and clientid = client_id and TRUNC(VISITFROM) =
TRUNC(TO_DATE(var_date, 'MM/DD/YYYY'))
and pkg_misc_functions.datepart('HH', VISITFROM) =
pkg_misc_functions.datepart('HH', var_from_in)
and pkg_misc_functions.datepart('MI', VISITFROM) =
pkg_misc_functions.datepart('MI', var_from_in)
and pkg_misc_functions.datepart('HH', VISITTO) =
pkg_misc_functions.datepart('HH', var_to_in)
and pkg_misc_functions.datepart('MI', VISITTO) =
pkg_misc_functions.datepart('MI', var_to_in);

if(var_v_count > 0)then


DBMS_OUTPUT.PUT_LINE('Sorry!, the carer has already been setup for this
period, client and time');
else
--var_date := '04/03/2016';
--check if the given date is within the specified period, if yes, then
continue
--else display message to prompt the user to try again with another
parameter.
select count(1) into var_p_count from period p where trunc(p.FROMDATETIME)
<= TO_DATE(var_date,'MM/DD/YYYY') AND
trunc(p.TODATETIME) >= TO_DATE(var_date,'MM/DD/YYYY');
if(var_p_count > 0)then
--check the day of the week (e.g. MONDAY) of the given date and check it
against the carer availability
select pkg_misc_functions.datename('DW', TO_DATE(var_date,'MM/DD/YYYY'))
into var_given_day_of_week from dual;
--We want to check the day of the week that a carer is available. i.e.
if the weekday (e.g. MONDAY)
-- specified by the input date is one of the days that the carer
specified as his/her availability
select count(dayoftheweek) into var_av_day_of_week from availability a
INNER JOIN carer_availability b on a.availabilityid =
b.availabilityid where b.carerid = var_carer_id and
upper(a.dayoftheweek) = trim(var_given_day_of_week) and
TO_DATE(A.FROMTIME, 'HH24:MI') <= TO_DATE(var_from_time,'HH24:MI') AND
TO_DATE(A.TOTIME, 'HH24:MI') >= TO_DATE(var_to_time,'HH24:MI');
DBMS_OUTPUT.PUT_LINE('The count of dayoftheweek in the table is: ' ||
var_av_day_of_week);
if(var_av_day_of_week > 0)then
add_result := PKG_TABLES_CREATION.CDSS_ADD_VISIT(var_carer_id,
client_id, var_period_id, var_manager_id, var_from_in, var_to_in);
if(add_result = 0)then
COMMIT;
DBMS_OUTPUT.PUT_LINE('Carer with carer id: ' || var_carer_id
|| ' has been successfully assigned to a client');
else
DBMS_OUTPUT.PUT_LINE('Error with Error Number: ' || add_result
|| ' has occured. Please consult the admin!');
end if;
else
DBMS_OUTPUT.PUT_LINE('Sorry! the carer is not available for
assignment on this day, please specify another day!');
end if;
else
DBMS_OUTPUT.PUT_LINE('Please specify the appropriate period to assign
visit for this carer,
the date specified does not match the period you want to assign');
end if;
end if;
exception
when others then
--PKG_MISC_FUNCTIONS.ORA_RAISERROR(sqlcode,sqlerrm,33);
DBMS_OUTPUT.PUT_LINE('Sorry! Error has occurred please contact the admin! or try
again later');

DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.format_error_backtrace);

Sample output of the condition

When the condition is fulfilled.

INNER JOIN 3 Description: It allows us to view all carers that are assigned to what clients by
what managers in what range of period and what range of time for visiting.

procedure prc_view_all_visit
is
CURSOR visit_all_cursor IS
--list all the list of carer, manager that assigned the carer, the clients they are
assigned to
--, etc at one glance.
SELECT C.FIRSTNAME || ' ' || C.LASTNAME CARER_NAME, CL.FIRSTNAME || ' ' ||
CL.LASTNAME CLIENT_NAME,
M.FIRSTNAME || ' ' || M.LASTNAME MANAGER_NAME, V.VISITFROM VISITING_FROM, V.VISITTO
VISITING_TO,
P.FROMDATETIME PERIOD_FROM, P.TODATETIME PERIOD_TO FROM CARER C INNER JOIN VISIT V
ON V.CARERID=C.CARERID INNER JOIN CLIENT CL ON V.CLIENTID = CL.CLIENTID
INNER JOIN PERIOD P ON V.PERIODID = P.PERIODID INNER JOIN MANAGER M ON
V.MANAGERID=M.MANAGERID;
selected_visit_row visit_all_cursor%ROWTYPE;
begin
OPEN visit_all_cursor;
FETCH visit_all_cursor INTO selected_visit_row;
DBMS_OUTPUT.PUT_LINE('LIST OF ALL ROSTERS');
DBMS_OUTPUT.PUT_LINE('');
DBMS_OUTPUT.PUT_LINE('CARERNAME' || CHR(9) || CHR(9) || CHR(9) ||
'CLIENTNAME' || CHR(9) || CHR(9) || CHR(9) || 'MANAGERNAME' || CHR(9) || CHR(9) ||
CHR(9) || 'VISITING_FROM' || CHR(9) || CHR(9) || 'VISITING_TO'
|| CHR(9) || CHR(9) || CHR(9) || CHR(9) || 'PERIOD_FROM' || CHR(9) ||
CHR(9) || CHR(9) || 'PERIOD_TO');
WHILE visit_all_cursor%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(selected_visit_row.CARER_NAME || CHR(9) ||
CHR(9) || CHR(9) || selected_visit_row.CLIENT_NAME || CHR(9) || CHR(9) || CHR(9) ||
selected_visit_row.MANAGER_NAME ||
CHR(9) || CHR(9) || CHR(9) || CHR(9) ||CHR(9) ||
selected_visit_row.VISITING_FROM || CHR(9) || CHR(9) ||CHR(9) || CHR(9) ||
selected_visit_row.VISITING_TO
|| CHR(9) || CHR(9) || CHR(9) || CHR(9) ||CHR(9) ||
selected_visit_row.PERIOD_FROM || CHR(9) || CHR(9) ||CHR(9) || CHR(9) ||
selected_visit_row.PERIOD_TO);

FETCH visit_all_cursor INTO selected_visit_row;


END LOOP;
CLOSE visit_all_cursor;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No data to display, sorry!');
WHEN others THEN
DBMS_OUTPUT.PUT_LINE('Error has occured please contact the admin!');
end;

After executing the procedure above, we have the list

INNER JOIN 4 and description: This shows individual carers roster for a period of time. So a
carer can just supply the carer number and the period number to get the roster.

6 OUTER JOIN (2 x left, 2 x full, 2 x right) queries with descriptions


FULL JOIN 1 and description: Show full list of cars both assigned and unassigned.

procedure prc_view_car_carer
is
CURSOR view_cursor IS
--list all the list of both carer and the car assigned and the car not assigned
SELECT CC.REG_NUMBER regno, CC.MODEL model, CC.ASSIGNED_DATE ass_date,
C.FIRSTNAME || ' ' || C.LASTNAME CARER_NAME FROM COMPANY_CAR CC FULL OUTER
JOIN CARER C ON
CC.ASSIGNED_TO_CARERID=C.CARERID;
selected_view_row view_cursor%ROWTYPE;
begin
OPEN view_cursor;
FETCH view_cursor INTO selected_view_row;
DBMS_OUTPUT.PUT_LINE('LIST OF ALL CARS AND CARERS');
DBMS_OUTPUT.PUT_LINE('');
DBMS_OUTPUT.PUT_LINE('REGISTRATION_NUMBER' || CHR(9) || CHR(9) || CHR(9) ||
'MODEL' || CHR(9) || CHR(9) || CHR(9) || 'ASSIGNED_DATE' || CHR(9) || CHR(9) ||
CHR(9) || 'CARER_NAME');
WHILE view_cursor%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(selected_view_row.regno || CHR(9) || CHR(9) ||
CHR(9) || selected_view_row.model || CHR(9) || CHR(9) || CHR(9) ||
selected_view_row.ass_date ||
CHR(9) || CHR(9) || CHR(9) || CHR(9) ||CHR(9) ||
selected_view_row.carer_name);
FETCH view_cursor INTO selected_view_row;
END LOOP;
CLOSE view_cursor;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No data to display, sorry!');
WHEN others THEN
DBMS_OUTPUT.PUT_LINE('Error has occured please contact the admin!');
end;

SELECT CC.REG_NUMBER regno, CC.MODEL model, CC.ASSIGNED_DATE ass_date,


C.FIRSTNAME || ' ' || C.LASTNAME CARER_NAME FROM COMPANY_CAR CC FULL OUTER
JOIN CARER C ON
CC.ASSIGNED_TO_CARERID=C.CARERID;

Using the procedure to execute


begin
pkg_scheduling_assignments.prc_view_car_carer;
end;/

FULL JOIN 2 and description: Show full list of all carers and the corresponding managers.
SELECT C.FIRSTNAME ||' ' || C.LASTNAME CARER_NAME, C.ADMINNOTE, M.FIRSTNAME ||' ' ||
M.LASTNAME MANAGER_NAME FROM CARER C FULL OUTER JOIN MANAGER M ON C.MANAGERID =
M.MANAGERID;

LEFT JOIN 1: and description: We want to list all the clients and some of their corresponding
comment information

select C.FIRSTNAME || ' ' || c.LASTNAME CLIENT_NAME, CC.DRESSING, CC.COMMUNICATION,


CC.HOUSEWORK, CC.MEDICATION, CC.SAFETY, CC.NUTRITION
from client c LEFT OUTER
JOIN COMMENTS CC ON
C.COMMENTID=CC.COMMENTID;

LEFT JOIN 2: We want to know the list of holidays dates from and to, that were booked by
what carer so that we have in the database in order to make business decisions on approving
or rejecting them.
SELECT H.HOLIDAYFROMDATE,
C.LASTNAME FROM HOLIDAY

H.HOLIDAYTODATE, H.NUMBEROFDAYS, H.STATUS, C.FIRSTNAME,


H LEFT OUTER JOIN CARER C ON H.CARERID=C.CARERID;

RIGHT JOIN 1: Here, we are interested in holidays date that all managers are involved in for
business decision
SELECT M.FIRSTNAME, M.LASTNAME, H.HOLIDAYFROMDATE, H.HOLIDAYTODATE FROM MANAGER M
RIGHT OUTER JOIN HOLIDAY H ON H.MANAGERID = M.MANAGERID

RIGHT JOIN 2: We are interested in getting the information about all carers who have applied
for holiday and their holiday approved or rejected, or who have not applied at all in order to
make business decision.
select H.HOLIDAYFROMDATE, H.HOLIDAYTODATE, H.NUMBEROFDAYS, H.STATUS, C.FIRSTNAME,
C.LASTNAME FROM holiday h RIGHT OUTER JOIN CARER C ON H.CARERID = C.CARERID;

1 CUBE query (with at least 2 columns


CUBE was used to count the number of holiday days each carer has booked
SELECT C.CARERID, H.HOLIDAYFROMDATE,
SUM(H.NUMBEROFDAYS) FROM HOLIDAY H INNER JOIN CARER C ON C.CARERID = H.CARERID
GROUP BY CUBE(C.CARERID, H.HOLIDAYFROMDATE );

5 examples of sub-queries
Sub-query 1: We want to get the number of days the carers hava taken in the booking year
before he/she is allowed to go to a new holiday. If the number of days for the year is greater
than the number allowed for that carer, we would report error.
select sum(numberofdays) into var_num_of_days from
holiday where carerid = selected_grant_row.carerid AND
PKG_MISC_FUNCTIONS.datepart('YY', HOLIDAYFROMDATE)=
(SELECT PKG_MISC_FUNCTIONS.datepart('YY', HOLIDAYFROMDATE) FROM
HOLIDAY WHERE
STATUS='BOOKED' AND CARERID = selected_grant_row.carerid);
DBMS_OUTPUT.PUT_LINE(' Number of days: ' || var_num_of_days);
select numberofdaysallowed into var_allowed from carer where
carerid = selected_grant_row.carerid;

Here is the full code where the subquery was implemented.


procedure prc_grant_holiday(var_manager_id number)
is
CURSOR grant_cursor IS
SELECT * FROM holiday WHERE status = 'BOOKED' and managerid = var_manager_id;
selected_grant_row grant_cursor%ROWTYPE;
var_allowed number;
var_num_of_days number;
update_h_result number;
update_ccr_result number;
var_status varchar2(15);
var_count_ass_cr_car number;
var_car_reg varchar2(40);
var_mgr_count number;

begin
select count(1) into var_mgr_count from manager where managerid =
to_number(var_manager_id);
if(var_mgr_count > 0)then
begin
OPEN grant_cursor;
FETCH grant_cursor INTO selected_grant_row;
WHILE grant_cursor%FOUND LOOP
--We want to get the number of days the carers hava taken in the
--booking year before he/she is allowed to go to a new holiday
select sum(numberofdays) into var_num_of_days from
holiday where carerid = selected_grant_row.carerid AND
PKG_MISC_FUNCTIONS.datepart('YY', HOLIDAYFROMDATE)=
(SELECT PKG_MISC_FUNCTIONS.datepart('YY', HOLIDAYFROMDATE) FROM
HOLIDAY WHERE
STATUS='BOOKED' AND CARERID = selected_grant_row.carerid);
DBMS_OUTPUT.PUT_LINE(' Number of days: ' || var_num_of_days);
select numberofdaysallowed into var_allowed from carer where
carerid = selected_grant_row.carerid;
DBMS_OUTPUT.PUT_LINE('Days allowed: ' || var_allowed);
if(var_num_of_days > var_allowed) then
DBMS_OUTPUT.PUT_LINE('Sorry! carer with Id: '||
selected_grant_row.carerid
|| ' has either finished holiday for the year or picked too much
new holiday. Please review and rebook, thank you!');
else
SAVEPOINT UPDATE_AND_UNASSIGN;
var_status := 'APPROVED';
DBMS_OUTPUT.PUT_LINE('value to send to update holiday: ' ||
var_status || ', carer id: ' || selected_grant_row.carerid
|| ', manager id: ' || var_manager_id);
update_h_result :=
pkg_tables_update.cdss_update_holiday(selected_grant_row.carerid, var_manager_id,
var_status);
if(update_h_result = 0) then
select count(1) into var_count_ass_cr_car from company_car
where assigned_to_carerid = selected_grant_row.carerid;
if(var_count_ass_cr_car > 0)then
select reg_number into var_car_reg from company_car
where assigned_to_carerid = selected_grant_row.carerid;
update_ccr_result :=
pkg_tables_update.cdss_update_car(var_car_reg);
if(update_ccr_result = 0)then
DBMS_OUTPUT.PUT_LINE('The holiday of Carer of
Carer Id: ' || selected_grant_row.carerid || ' has been granted, but the car has
been deallocated');
COMMIT;
else
DBMS_OUTPUT.PUT_LINE('Sorry! we cannot
deallocate the car assigned to this carer with id: '|| selected_grant_row.carerid ||
'at the moment, and all the transactions are now rolled back for the carer.
Pls contact the administrator or try again
later.');
ROLLBACK TO UPDATE_AND_UNASSIGN;
end if;
else
DBMS_OUTPUT.PUT_LINE('The holiday of Carer of Carer
Id: ' || selected_grant_row.carerid || ' has been granted, and no car to
deallocate');
COMMIT;

end if;
else
DBMS_OUTPUT.PUT_LINE('Sorry! we cannot update the holiday
information for carer with id: '|| selected_grant_row.carerid || 'at the moment, and
all the transactions are now rolled back for the carer.
Pls contact the administrator or try again
later.');
ROLLBACK TO UPDATE_AND_UNASSIGN;
end if;
end if;

FETCH grant_cursor INTO selected_grant_row;


END LOOP;
CLOSE grant_cursor;
end;
else
DBMS_OUTPUT.PUT_LINE('The manager specified does not exist. Sorry!');
end if;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No data for the manager to process. Sorry!');
end;

Sub-query 2: We are checking for carers who have applied for holiday more than once in a
given year, and we gave 2016 as an example.
--check for carers who have applied for holiday more than once in a given year in
this case, 2016
select C.FIRSTNAME, C.LASTNAME from carer c where c.carerid in
(select carerid from holiday WHERE pkg_misc_functions.datepart('YY',
HOLIDAYFROMDATE) = '2016' having count(numberofdays) > 1 Group by carerid);

Sub-query 3: This query with subqueries check if a carer who want to cover is also on holiday
before being assigned to cover another carer.

--check if the carer is also on holiday


select count(1) into var_on_hol from holiday h where h.carerid =
var_cover_id and
h.HOLIDAYFROMDATE <= (select trunc(VISITFROM) from visit where visitid =
var_visit_id)
and H.HOLIDAYTODATE >= (select TRUNC(VISITTO) from visit where visited =
var_visit_id);
DBMS_OUTPUT.PUT_LINE('Check if cover is on holiday too, using variable
val_on_hol to count: ' || var_on_hol);
if(var_cover_id = var_carer_id)then
DBMS_OUTPUT.PUT_LINE('Sorry, A carer cannot cover for
himself/herself!');
elsif(var_on_hol > 0) then
DBMS_OUTPUT.PUT_LINE('Sorry, the cover is on holiday too at the time');

-- check if the cover carer is also on visit at the time


select count(1) into var_on_visit from visit where carerid =
var_cover_id and
VISITFROM <= (select VISITFROM from visit where visitid =var_visit_id)
and VISITTO >= (select VISITTO from visit where visitid =var_visit_id);
DBMS_OUTPUT.PUT_LINE('Check if cover is on visit at the time too using
var_on_visit to count: ' || var_on_visit);
if(var_on_visit > 0)then
DBMS_OUTPUT.PUT_LINE('Sorry, the cover is also on duty at the time!');

Sub-query 4: This query with subqueries check if a carer who want to cover has a visit at the
time too, since a carer cannot be at more than one places at a time, it is meaningless to let
them be able to assign any carer just any how.

Sub-query 5: We want to know the list of carers that have choosen their availability so that
we can assign them to clients. Only carers with availability Id would be assigned.
--all the Carer that have set up their availability
select firstname, lastname, dateofbirth from carer where carerid in
(select distinct carerid from carer_availability)

5 PL/SQL procedures as part of one package. One procedure must


demonstrate each of the following:
The procedures showing here are in one package called pkg_scheduling_assignments
Procedure 1:
The use of a cursor, save points and rollback: This procedure is one of the many procedures
developed for this application and it duely makes use of cursor, savepoints and rollback. In
order to grant holiday to a carer, we would first check if such carer has a car given to
him/her to go to the clients, and that he/she is eligible for holiday based on some controls
including whether he has expended his holiday for the year he is trying to book holiday for or
not. If all conditions are met, we would proceed to approving holiday. Then the car is
deallocated from such carer until he/she is back so that others can make use of the car to
visit clients. So the transaction that saves the approval will be rolled back in case of error or
something terrible happened during the approval. This means that both the update for the
holiday and deallocation of the car would have to be successful. If update holiday has error,
it is rolled back.
We are using cursor to loop through each carer that has status BOOKED and belonging to
one manager, so that the manager only need to hit one button to approve or reject holiday
booking by each carer under them.
procedure prc_grant_holiday(var_manager_id number)
is
CURSOR grant_cursor IS
SELECT * FROM holiday WHERE status = 'BOOKED' and managerid = var_manager_id;
selected_grant_row grant_cursor%ROWTYPE;
var_allowed number;
var_num_of_days number;
update_h_result number;
update_ccr_result number;
var_status varchar2(50);
var_count_ass_cr_car number;
var_car_reg varchar2(40);
var_mgr_count number;
begin
select count(1) into var_mgr_count from manager where managerid = var_manager_id;
if(var_mgr_count > 0)then
begin
OPEN grant_cursor;
FETCH grant_cursor INTO selected_grant_row;
WHILE grant_cursor%FOUND LOOP
--We want to get the number of days the carers hava taken in the
booking year
--before he/she is allowed to go to a new holiday
DBMS_OUTPUT.PUT_LINE(' Inside loop carer ' ||
selected_grant_row.carerid );
select sum(numberofdays) into var_num_of_days from
holiday where carerid = selected_grant_row.carerid AND
PKG_MISC_FUNCTIONS.datepart('YY', HOLIDAYFROMDATE)=
(SELECT PKG_MISC_FUNCTIONS.datepart('YY', HOLIDAYFROMDATE) FROM
HOLIDAY WHERE

STATUS='BOOKED' AND CARERID = selected_grant_row.carerid);


DBMS_OUTPUT.PUT_LINE(' Number of days: ' || var_num_of_days);
select numberofdaysallowed into var_allowed from carer where
carerid = selected_grant_row.carerid;
DBMS_OUTPUT.PUT_LINE('Days allowed: ' || var_allowed);
if(var_num_of_days > var_allowed) then
var_status := 'REJECTED, TOO MANY DAYS';
update_h_result :=
pkg_tables_update.cdss_update_holiday(selected_grant_row.carerid, var_manager_id,
var_status);
if(update_h_result = 0)then
commit;
DBMS_OUTPUT.PUT_LINE('Sorry! the holiday has been rejected,
please update');
else
DBMS_OUTPUT.PUT_LINE('Error updating the rejection');
end if;
DBMS_OUTPUT.PUT_LINE('Sorry! carer with Id: '||
selected_grant_row.carerid
|| ' has either finished holiday for the year or picked too much
new holiday. Please review and rebook, thank you!');
else
SAVEPOINT UPDATE_AND_UNASSIGN;
var_status := 'APPROVED';
DBMS_OUTPUT.PUT_LINE('value to send to update holiday: ' ||
var_status || ', carer id: ' || selected_grant_row.carerid
|| ', manager id: ' || var_manager_id);
update_h_result :=
pkg_tables_update.cdss_update_holiday(selected_grant_row.carerid, var_manager_id,
var_status);
if(update_h_result = 0) then
select count(1) into var_count_ass_cr_car from company_car
where assigned_to_carerid = selected_grant_row.carerid;
if(var_count_ass_cr_car > 0)then
select reg_number into var_car_reg from company_car
where assigned_to_carerid = selected_grant_row.carerid;
update_ccr_result :=
pkg_tables_update.cdss_update_car(var_car_reg);
if(update_ccr_result = 0)then
COMMIT;
DBMS_OUTPUT.PUT_LINE('The holiday of Carer of
Carer Id: ' || selected_grant_row.carerid || ' has been granted, but the car has
been deallocated');
else
ROLLBACK TO UPDATE_AND_UNASSIGN;
DBMS_OUTPUT.PUT_LINE('Sorry! we cannot
deallocate the car assigned to this carer with id: '|| selected_grant_row.carerid ||
'at the moment, and all the transactions are now rolled back for the carer.
Pls contact the administrator or try again
later.');
end if;
else
COMMIT;
DBMS_OUTPUT.PUT_LINE('The holiday of Carer of Carer
Id: ' || selected_grant_row.carerid || ' has been granted, and no car to
deallocate');
end if;

else
ROLLBACK TO UPDATE_AND_UNASSIGN;
DBMS_OUTPUT.PUT_LINE('Sorry! we cannot update the holiday
information for carer with id: '|| selected_grant_row.carerid || 'at the moment, and
all the transactions are now rolled back for the carer.
Pls contact the administrator or try again
later.');
end if;
end if;

FETCH grant_cursor INTO selected_grant_row;


END LOOP;
CLOSE grant_cursor;
end;
else
DBMS_OUTPUT.PUT_LINE('The manager specified does not exist. Sorry!');
end if;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No data for the manager to process. Sorry!');
end;

We used grant holiday procedure below to grant all carers who are a being managed by a
manager 1000 holidays and unassign cars from them in order to assign it to another person for
work purpose.
begin
pkg_scheduling_assignments.prc_grant_holiday(1000);
end;

Procedure 2:
This procedure is used to assign a cover to a carer, the cover is also a carer but can only
cover for another if he/she is not on holiday and not having a client to attend to at the same
time of the cover.

procedure prc_assign_cover(var_manager_id number)


as
var_cover_id number;
var_carer_id number;
var_on_hol number;
var_on_visit number;
var_result number;
var_reason varchar2(70);
var_visit_id number;
begin
var_cover_id := 1024;
var_carer_id := 1004;
var_reason := 'The carer is on Holiday';
var_visit_id := 18;
--check if the carer is also on holiday
select count(1) into var_on_hol from holiday h where h.carerid =
var_cover_id and
h.HOLIDAYFROMDATE <= (select trunc(VISITFROM) from visit where visitid =
var_visit_id)
and H.HOLIDAYTODATE >= (select TRUNC(VISITTO) from visit where
visitid=var_visit_id);
DBMS_OUTPUT.PUT_LINE('Check if cover is on holiday too, using variable
val_on_hol to count: ' || var_on_hol);
if(var_cover_id = var_carer_id)then
DBMS_OUTPUT.PUT_LINE('Sorry, A carer cannot cover for
himself/herself!');
elsif(var_on_hol > 0) then
DBMS_OUTPUT.PUT_LINE('Sorry, the cover is on holiday too at the time');
else
-- check if the cover carer is also on visit at the time
select count(1) into var_on_visit from visit where carerid =
var_cover_id and
VISITFROM <= (select VISITFROM from visit where visitid =var_visit_id)
and VISITTO >= (select VISITTO from visit where visitid =var_visit_id);
DBMS_OUTPUT.PUT_LINE('Check if cover is on visit at the time too using
var_on_visit to count: ' || var_on_visit);
if(var_on_visit > 0)then
DBMS_OUTPUT.PUT_LINE('Sorry, the cover is also on duty at the
time!');
else
var_result := PKG_TABLES_CREATION.CDSS_ADD_COVER(var_carer_id,
var_cover_id, var_reason, var_visit_id);
if(var_result = 0)then
DBMS_OUTPUT.PUT_LINE('Congratulations! Cover for carer with id:
' || var_carer_id
|| ' has been successfully found. Carer with Carer id: ' ||
var_cover_id || ' will cover');

COMMIT;
else
DBMS_OUTPUT.PUT_LINE('Oops! we cannot save cover information at
the moment. Please try again later!');
end if;
end if;
end if;
end;

Procedure 3:
This procedure is used to assign a carer to a availability. The carers can choose different days
of the week that they are going to be available for work.
Example:
begin
PKG_SCHEDULING_ASSIGNMENTS.PRC_ASSIGN_CARER_TO_AVAIL(1026, 27, 1033);
end;/

procedure prc_assign_carer_to_avail(var_carer_id number, var_availability_id number,


var_manager_id number)
as
result number;
var_count_c_a number;
var_count_mgr number;
begin
select count(1) into var_count_c_a from carer_availability where carerid =
var_carer_id and availabilityid = var_availability_id;
select count(1) into var_count_mgr from manager where managerid =
var_manager_id;
if(var_count_mgr > 0)then
begin
if(var_count_c_a > 0)then
DBMS_OUTPUT.PUT_LINE('Sorry! This Carer has been assigned to this
availability before
Please specify another carer or another availability. Thank you!');
else
begin
--we return 0 everytime the insertion is successful
result :=
pkg_tables_creation.cdss_add_carer_availability(var_carer_id, var_availability_id);

if(result = 0) then
COMMIT;
DBMS_OUTPUT.PUT_LINE('Carer availability has been successfully
inserted: ');
else
DBMS_OUTPUT.PUT_LINE('Sorry! the carer cannot be assigned at the
moment, we have error: '
|| result || ' please contact administrator');
end if;
end;
end if;
end;
else
DBMS_OUTPUT.PUT_LINE('Sorry! this manager id ' || var_manager_id ||
' does not exist, only existing manager can insert data');
end if;
end;

if the manager id does not exist

If the carer has already been assigned

When the data is correct

Procedure 4:
The procedure is used to assign carer to client with the help of the carer_availability selected
by the carer above and at a particular period. This is assigned by a manager assigned to the
carer.
Example of calling of the procedure:
declare
add_result number;
var_v_count number;
var_p_count number;
var_count_mgr number;
var_manager_id number;
var_from_date varchar2(50);
var_to_date varchar2(50);
var_to_in timestamp;
var_from_in timestamp;
var_given_day_of_week varchar2(15);
var_av_day_of_week NUMBER;
var_date varchar2(30);
var_from_time varchar2(30);
var_to_time varchar2(30);
var_carer_id number;
client_id number;
var_period_id number;
begin
var_carer_id:= 1003;
var_manager_id := 1002;
var_date := '4/4/2016';
var_from_time := '10:00';
var_to_time := '12:00';
client_id := 300;
var_period_id := 2;
pkg_scheduling_assignments.prc_schedule_visit(var_carer_id, client_id,
var_period_id,
var_manager_id, var_date, var_from_time, var_to_time);
end;

The procedure creation


procedure prc_schedule_visit(var_carer_id number, client_id number, var_period_id
number,
var_manager_id number, var_date varchar2, var_from_time varchar2, var_to_time
varchar2)
as
add_result number;
var_v_count number;
var_p_count number;
var_count_mgr number;
var_v_count_cl number;
var_v_count_cr number;
var_from_date varchar2(50);
var_to_date varchar2(50);
var_to_in timestamp;
var_from_in timestamp;

var_given_day_of_week varchar2(15);
var_av_day_of_week NUMBER;
begin
var_from_date := var_date ||' ' || var_from_time;
var_to_date := var_date ||' ' || var_to_time;
var_from_in:= TO_DATE(var_from_date, 'MM/DD/YYYY HH24:MI');
var_to_in := TO_DATE(var_to_date, 'MM/DD/YYYY HH24:MI');
--check if the carer has been assigned to this client for this period and
this time before
--if yes show response if not, continue to the next line of action.
select count(1) into var_v_count from visit where periodid = var_period_id
and
carerid = var_carer_id and clientid = client_id and TRUNC(VISITFROM) =
TRUNC(TO_DATE(var_date, 'MM/DD/YYYY'))
and pkg_misc_functions.datepart('HH', VISITFROM) =
pkg_misc_functions.datepart('HH', var_from_in)
and pkg_misc_functions.datepart('MI', VISITFROM) =
pkg_misc_functions.datepart('MI', var_from_in)
and pkg_misc_functions.datepart('HH', VISITTO) =
pkg_misc_functions.datepart('HH', var_to_in)
and pkg_misc_functions.datepart('MI', VISITTO) =
pkg_misc_functions.datepart('MI', var_to_in);
--check if the carer has been assigned to another client at the time, so he
does not get assigned
-- to 2 or more clients at a time
select count(1) into var_v_count_cl from visit where periodid = var_period_id
and
carerid = var_carer_id and TRUNC(VISITFROM) = TRUNC(TO_DATE(var_date,
'MM/DD/YYYY'))
and pkg_misc_functions.datepart('HH', VISITFROM) =
pkg_misc_functions.datepart('HH', var_from_in)
and pkg_misc_functions.datepart('MI', VISITFROM) =
pkg_misc_functions.datepart('MI', var_from_in)
and pkg_misc_functions.datepart('HH', VISITTO) =
pkg_misc_functions.datepart('HH', var_to_in)
and pkg_misc_functions.datepart('MI', VISITTO) =
pkg_misc_functions.datepart('MI', var_to_in);
--check if the time has been booked for that client with another carer
select count(1) into var_v_count_cr from visit where periodid = var_period_id
and
clientid = client_id and TRUNC(VISITFROM) = TRUNC(TO_DATE(var_date,
'MM/DD/YYYY'))
and pkg_misc_functions.datepart('HH', VISITFROM) =
pkg_misc_functions.datepart('HH', var_from_in)
and pkg_misc_functions.datepart('MI', VISITFROM) =
pkg_misc_functions.datepart('MI', var_from_in)
and pkg_misc_functions.datepart('HH', VISITTO) =
pkg_misc_functions.datepart('HH', var_to_in)
and pkg_misc_functions.datepart('MI', VISITTO) =
pkg_misc_functions.datepart('MI', var_to_in);
if(var_v_count > 0)then
--If carer already exist for the same client
DBMS_OUTPUT.PUT_LINE('Sorry!, the carer has already been setup for this
period, client and time');
elsif(var_v_count_cl > 0) then
--if carer has been scheduled with another client

DBMS_OUTPUT.PUT_LINE('Sorry!, the carer has already been setup for this


period, to another client at the same time');
elsif(var_v_count_cr > 0) then
--if carer has been scheduled with another client
DBMS_OUTPUT.PUT_LINE('Sorry!, the client has already been setup for this
period, to another carer at the same time');
else
--var_date := '04/03/2016';
--check if the given date is within the specified period, if yes, then
continue
--else display message to prompt the user to try again with another
parameter.
select count(1) into var_p_count from period p where trunc(p.FROMDATETIME)
<= TO_DATE(var_date,'MM/DD/YYYY') AND
trunc(p.TODATETIME) >= TO_DATE(var_date,'MM/DD/YYYY');
if(var_p_count > 0)then
--check the day of the week (e.g. MONDAY) of the given date and check it
against the carer availability
select pkg_misc_functions.datename('DW', TO_DATE(var_date,'MM/DD/YYYY'))
into var_given_day_of_week from dual;
--We want to check the day of the week that a carer is available. i.e.
if the weekday (e.g. MONDAY)
-- specified by the input date is one of the days that the carer
specified as his/her availability
select count(dayoftheweek) into var_av_day_of_week from availability a
INNER JOIN carer_availability b on a.availabilityid =
b.availabilityid where b.carerid = var_carer_id and
upper(a.dayoftheweek) = trim(var_given_day_of_week) and
TO_DATE(A.FROMTIME, 'HH24:MI') <= TO_DATE(var_from_time,'HH24:MI') AND
TO_DATE(A.TOTIME, 'HH24:MI') >= TO_DATE(var_to_time,'HH24:MI');
DBMS_OUTPUT.PUT_LINE('The count of dayoftheweek in the table is: ' ||
var_av_day_of_week);
if(var_av_day_of_week > 0)then
add_result := PKG_TABLES_CREATION.CDSS_ADD_VISIT(var_carer_id,
client_id, var_period_id, var_manager_id, var_from_in, var_to_in);
if(add_result = 0)then
COMMIT;
DBMS_OUTPUT.PUT_LINE('Carer with carer id: ' || var_carer_id
|| ' has been successfully assigned to a client');
else
DBMS_OUTPUT.PUT_LINE('Error with Error Number: ' || add_result
|| ' has occured. Please consult the admin!');
end if;
else
DBMS_OUTPUT.PUT_LINE('Sorry! the carer is not available for
assignment on this day, please specify another day!');
end if;
else
DBMS_OUTPUT.PUT_LINE('Please specify the appropriate period to assign
visit for this carer,
the date specified does not match the period you want to assign');
end if;
end if;
exception
when others then

--PKG_MISC_FUNCTIONS.ORA_RAISERROR(sqlcode,sqlerrm,33);
DBMS_OUTPUT.PUT_LINE('Sorry! Error has occurred please contact the admin! or try
again later');
DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.format_error_backtrace);
end;

When the data is already existing in the database

When the carer has not selected the availability

When it is successful.

Procedure 5:
The procedure shows the list of rosters of one carer based on a range of period. So the carer
can specify the period id and his/her carer id in order to show it.
Example of calling of the procedure:
begin
pkg_scheduling_assignments.prc_view_all_visit(1003, 2);
end;/

procedure prc_view_all_visit(var_carer_id number, var_period_id number)


is
CURSOR visit_all_cursor IS
--list all the list of carer, manager that assigned the carer, the clients they are
assigned to
--, etc at one glance.
SELECT C.FIRSTNAME || ' ' || C.LASTNAME CARER_NAME, CL.FIRSTNAME || ' ' ||
CL.LASTNAME CLIENT_NAME,
M.FIRSTNAME || ' ' || M.LASTNAME MANAGER_NAME, V.VISITFROM VISITING_FROM, V.VISITTO
VISITING_TO,
P.FROMDATETIME PERIOD_FROM, P.TODATETIME PERIOD_TO FROM CARER C INNER JOIN VISIT V
ON V.CARERID=C.CARERID INNER JOIN CLIENT CL ON V.CLIENTID = CL.CLIENTID
INNER JOIN PERIOD P ON V.PERIODID = P.PERIODID INNER JOIN MANAGER M ON
V.MANAGERID=M.MANAGERID
AND C.CARERID=var_carer_id and P.PERIODID=var_period_id;
selected_visit_row visit_all_cursor%ROWTYPE;
begin
OPEN visit_all_cursor;
FETCH visit_all_cursor INTO selected_visit_row;
DBMS_OUTPUT.PUT_LINE('LIST OF CARER '|| var_carer_id || ' ROSTER');
DBMS_OUTPUT.PUT_LINE('');
DBMS_OUTPUT.PUT_LINE('CARERNAME' || CHR(9) || CHR(9) || CHR(9) ||
'CLIENTNAME' || CHR(9) || CHR(9) || CHR(9) || 'MANAGERNAME' || CHR(9) || CHR(9) ||
CHR(9) || 'VISITING_FROM' || CHR(9) || CHR(9) || 'VISITING_TO'

|| CHR(9) || CHR(9) || CHR(9) || CHR(9) || 'PERIOD_FROM' || CHR(9) ||


CHR(9) || CHR(9) || 'PERIOD_TO');
WHILE visit_all_cursor%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(selected_visit_row.CARER_NAME || CHR(9) ||
CHR(9) || CHR(9) || selected_visit_row.CLIENT_NAME || CHR(9) || CHR(9) || CHR(9) ||
selected_visit_row.MANAGER_NAME ||
CHR(9) || CHR(9) || CHR(9) || CHR(9) ||CHR(9) ||
selected_visit_row.VISITING_FROM || CHR(9) || CHR(9) ||CHR(9) || CHR(9) ||
selected_visit_row.VISITING_TO
|| CHR(9) || CHR(9) || CHR(9) || CHR(9) ||CHR(9) ||
selected_visit_row.PERIOD_FROM || CHR(9) || CHR(9) ||CHR(9) || CHR(9) ||
selected_visit_row.PERIOD_TO);
FETCH visit_all_cursor INTO selected_visit_row;
END LOOP;
CLOSE visit_all_cursor;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No data to display, sorry!');
WHEN others THEN
DBMS_OUTPUT.PUT_LINE('Error has occured please contact the admin!');
end;

There are other procedures in the other packages and in the package made use of in this
section.

2 PL/SQL functions
There are lots of functions made use of in this program, all the insertions are performed with
the use of functions. Then we have a miscellaneous function that is always in handy in the
application to get the day of the week, hours, minutes, seconds, days. Others also get
differences between 2 dates which might be hours difference, days difference, week
differences etc. I will just pick 2 of the functions to explain here.

Function 1.
During holiday booking, an anonymous plsql was written where a function cdss_add_holiday
belonging to pkg_tables_creation was called in order to book holiday by carers.
This allows carers to book holiday. Error is displayed if the user has already booked a holiday
that has not been approved or rejected.
Example:
declare
var_care_id number;
var_manager_id number;
var_status varchar2(30);
var_managerid number;
var_holiday_from_date date;
var_holiday_to_date DATE;
insert_result number;
v_count number;
begin
var_care_id := 1025;
var_manager_id := 1033;
var_status := 'BOOKED';
var_holiday_from_date := TO_DATE('4/5/2016', 'MM/DD/YYYY');
var_holiday_to_date := TO_DATE('4/14/2016', 'MM/DD/YYYY');
select count(1) into v_count from holiday where CARERID=var_care_id and
STATUS='BOOKED';
if(v_count > 0)then
DBMS_OUTPUT.PUT_LINE('Sorry, you still have a booking that has not been approved
yet');
Else
--function that calls the book holiday
insert_result := PKG_TABLES_CREATION.cdss_add_holiday(var_care_id,
var_manager_id, var_holiday_from_date, var_holiday_to_date, var_status);
if(insert_result = 0)then
COMMIT;
DBMS_OUTPUT.PUT_LINE('Holiday booking was successful the manager will access
it soon');
else
DBMS_OUTPUT.PUT_LINE('Error has occured during booking');
end if;
end if;
exception
when others then
DBMS_OUTPUT.PUT_LINE('Error has occured ');
DBMS_OUTPUT.PUT_LINE(DBMS_UTILITY.format_error_backtrace);
end;/

Here is the function

FUNCTION cdss_add_holiday(var_carerid
number, var_managerid number,
var_holiday_from_date
DATE, var_holiday_to_date DATE, var_status
varchar2
) return number
as
var_duration number;
no_rows exception;
v_l_retval number;
begin
begin
var_duration := PKG_MISC_FUNCTIONS.datediff('DD',
var_holiday_from_date, var_holiday_to_date);
INSERT INTO holiday
(
CARERID,
MANAGERID,
HOLIDAYFROMDATE,
NUMBEROFDAYS,
STATUS,
HOLIDAYTODATE
values

)
(
var_carerid,
var_managerid,
var_holiday_from_date,
var_duration,
var_status,
var_holiday_to_date
);

if sql%rowcount != 1 then
raise no_rows;
end if;
exception
when no_rows then
DBMS_OUTPUT.PUT_LINE('No rows inserted for cdss_add_holiday');
PKG_MISC_FUNCTIONS.ORA_RAISERROR(sqlcode, 'No rows inserted for
cdss_add_holiday', 22);
return 5694;
when others then
DBMS_OUTPUT.PUT_LINE('Insert failed for cdss_add_holiday');
PKG_MISC_FUNCTIONS.ORA_RAISERROR(sqlcode, 'Insert failed for
cdss_add_holiday', 25);
return sqlcode;
end;
return 0;
exception
when others then
DBMS_OUTPUT.PUT_LINE('Execution of cdss_add_holiday failed');
PKG_MISC_FUNCTIONS.ORA_RAISERROR(sqlcode, 'Execution of
cdss_add_holiday failed', 104);
return 95;
end;

When the holiday is successfully booked

When the carer has booked before and the manager has not reply (either approve or reject)

Function 2.
The datediff function is situated in pkg_misc_functions package it is used in the program
to get the duration between two dates which may be year, weeks, days, hours, minutes
or seconds difference. It was used inside the

function datediff(fmt VARCHAR2, dat1 DATE, dat2 DATE) return INTEGER as


rint INTEGER;
begin
if (fmt = 'DD') then
rint := trunc(dat2) - trunc(dat1);
end if;
if (fmt = 'MM') then
rint := MONTHS_BETWEEN(last_day(dat2), last_day(dat1));
end if;
if (fmt = 'YY') then
rint := datepart(yy, dat2) - datepart(yy, dat1);
end if;
if (fmt = 'HH') then
rint := ((trunc(dat2) - trunc(dat1)) * 24) +
(datepart(hh, dat2) - datepart(hh, dat1));
end if;
if (fmt = 'MI') then
rint := ((datediff(hh, dat1, dat2)) * 60) +
(datepart(mi, dat2) - datepart(mi, dat1));
end if;
if (fmt = 'SS') then
rint := ((datediff(mi, dat1, dat2)) * 60) +
(datepart(ss, dat2) - datepart(ss, dat1));
end if;
if(fmt = 'WK')then
select trunc((dat2-dat1)/7) into rint from dual;
end if;
return rint;
end;

Where it was used


FUNCTION cdss_add_holiday(var_carerid
number, var_managerid number,
var_holiday_from_date
DATE, var_holiday_to_date DATE, var_status
varchar2
) return number
as
var_duration number;
no_rows exception;
v_l_retval number;
begin
begin
--get differences based on number of days
var_duration := PKG_MISC_FUNCTIONS.datediff('DD',
var_holiday_from_date, var_holiday_to_date);
INSERT INTO holiday
(
CARERID,
MANAGERID,
HOLIDAYFROMDATE,
NUMBEROFDAYS,
STATUS,
HOLIDAYTODATE
values

)
(
var_carerid,
var_managerid,
var_holiday_from_date,

var_duration,
var_status,
var_holiday_to_date
);
if sql%rowcount != 1 then
raise no_rows;
end if;
exception
when no_rows then
DBMS_OUTPUT.PUT_LINE('No rows inserted for cdss_add_holiday');
PKG_MISC_FUNCTIONS.ORA_RAISERROR(sqlcode, 'No rows inserted for
cdss_add_holiday', 22);
return 5694;
when others then
DBMS_OUTPUT.PUT_LINE('Insert failed for cdss_add_holiday');
PKG_MISC_FUNCTIONS.ORA_RAISERROR(sqlcode, 'Insert failed for
cdss_add_holiday', 25);
return sqlcode;
end;
return 0;
exception
when others then
DBMS_OUTPUT.PUT_LINE('Execution of cdss_add_holiday failed');
PKG_MISC_FUNCTIONS.ORA_RAISERROR(sqlcode, 'Execution of
cdss_add_holiday failed', 104);
return 95;
end;

It was also used in function cdss_add_period in order to find the differences in weeks between
periods.

FUNCTION cdss_add_period(var_from_date_time date,


var_to_date_time date) return number
as
var_duration number;
no_rows exception;
v_l_retval number;
begin
-- The period is a range of time that carers get assigned to clients newly.
Mostly, carers
--get assigned in 3 weeks
--PKG_MISC_FUNCTIONS.datediff is getting the duration of the period which
maybe 2 weeks or 3 weeks,
-- So the var_duration here return weeks, so if you have 1 it means 1 week,
and if 2 it means 2 weeks
begin
--get difference based on weeks
var_duration := PKG_MISC_FUNCTIONS.datediff('WK',
var_from_date_time, var_to_date_time);
DBMS_OUTPUT.PUT_LINE('The number of weeks between ' || var_from_date_time || ' and
' ||
var_to_date_time || ' is ' || var_duration);
if(var_duration < 1)then
return -1;
elsif(var_duration > 1) then

INSERT INTO PERIOD


(
FROMDATETIME,
TODATETIME,
DURATION
)
values (
var_from_date_time,
var_to_date_time,
var_duration
);
end if;
if sql%rowcount != 1 then
raise no_rows;
end if;
exception
when no_rows then
DBMS_OUTPUT.PUT_LINE('No rows inserted for cdss_add_period');
PKG_MISC_FUNCTIONS.ORA_RAISERROR(sqlcode, 'No rows inserted for
cdss_add_period', 22);
return 5694;
when others then
DBMS_OUTPUT.PUT_LINE('Insert failed for cdss_add_period');
PKG_MISC_FUNCTIONS.ORA_RAISERROR(sqlcode, 'Insert failed for
cdss_add_period', 25);
return sqlcode;
end;
return 0;
exception
when others then
DBMS_OUTPUT.PUT_LINE('Execution of cdss_add_period failed');
PKG_MISC_FUNCTIONS.ORA_RAISERROR(sqlcode, 'Execution of
cdss_add_period failed', 104);
return 95;
end;

Another function is datename that was used in the application to get the name of the week

function datename(fmt IN VARCHAR2, miscdate IN DATE) return VARCHAR2 as


rexp VARCHAR2(15);
begin
if (fmt = 'DD') then
rexp := to_char(miscdate, 'DD');
end if;
if (fmt = 'MM') then
rexp := to_char(miscdate, 'Month');
end if;
if (fmt = 'YY') then
rexp := to_char(miscdate, 'YYYY');
end if;
if (fmt = 'QQ') then
rexp := to_char(miscdate, 'Q');

end if;
if (fmt = 'WK') then
rexp := to_char(miscdate,
end if;
if (fmt = 'DY') then
rexp := to_char(miscdate,
end if;
if (fmt = 'DW') then
rexp := to_char(miscdate,
end if;
if (fmt = 'Dw') then
rexp := to_char(miscdate,
end if;
if (fmt = 'dw') then
rexp := to_char(miscdate,
end if;
if (fmt = 'HH') then
rexp := to_char(miscdate,
end if;
if (fmt = 'MI') then
rexp := to_char(miscdate,
end if;
if (fmt = 'SS') then
rexp := to_char(miscdate,
end if;
return rexp;
end;

'WW');
'DDD');
'DAY');
'Day');
'day');
'HH24');
'MI');
'SS');

var_duration := PKG_MISC_FUNCTIONS.datediff('WK',
var_from_date_time, var_to_date_time);
DBMS_OUTPUT.PUT_LINE('The number of weeks between ' || var_from_date_time || ' and
' ||
var_to_date_time || ' is ' || var_duration);

The specified above generates the screenshot below:

3 Triggers (at least 1 before, and at least 1 after)


Trigger 1
The trigger was created for all the auto increment ids in order to combine with the created
sequence to be triggered before each insertion.
CREATE SEQUENCE MGR_CARER_SEQ
START WITH 1000
INCREMENT BY 1 NOMAXVALUE;
--TRIGGERS
CREATE OR REPLACE TRIGGER MGR_INSERTION_TRIGGER
BEFORE INSERT ON MANAGER FOR EACH ROW
BEGIN
SELECT MGR_CARER_SEQ.NEXTVAL INTO :NEW.MANAGERID FROM DUAL;
END;
/

Trigger 2
This trigger shows whenever a carer tries to select more than 20 days of holiday at once.
CREATE OR REPLACE TRIGGER HOL_GT_20
BEFORE INSERT OR UPDATE OF NUMBEROFDAYS ON HOLIDAY
FOR EACH ROW
WHEN (New.NUMBEROFDAYS > 20)
BEGIN
DBMS_OUTPUT.PUT_LINE('The carer with carer id: ' || :NEW.carerid || ' cannot have
more than 20 days holiday at once');
DBMS_OUTPUT.PUT_LINE('The Updated or Inserted number of days is: ' ||
:NEW.NUMBEROFDAYS);
END;
/

Trigger 3: This is an after trigger that triggers whenever there is an insert, update or delete
into company_car table, this is a companys asset and it needs to be monitored to know know
whenever someone makes a change to it. In the trigger, we captured the user that performed
the act too.

CREATE OR REPLACE TRIGGER COMPANY_CAR_TRIGGER


AFTER INSERT OR DELETE OR UPDATE ON COMPANY_CAR
FOR EACH ROW
DECLARE
v_username varchar2(50);
BEGIN
SELECT user INTO v_username FROM dual;
IF INSERTING THEN
INSERT INTO COMPANY_CAR_AUDIT ( REG_NUMBER, MODEL, ASSIGNED_TO_CARERID,
ASSIGNED_DATE, operation, WHO)
VALUES (:NEW.REG_NUMBER,:NEW.MODEL, :NEW.ASSIGNED_TO_CARERID ,
:NEW.ASSIGNED_DATE,
'Insert ', v_username);
ELSIF DELETING THEN
INSERT INTO COMPANY_CAR_AUDIT ( REG_NUMBER, MODEL, ASSIGNED_TO_CARERID,
ASSIGNED_DATE, operation, WHO)
VALUES (:NEW.REG_NUMBER,:NEW.MODEL, :NEW.ASSIGNED_TO_CARERID ,
:NEW.ASSIGNED_DATE,
'Delete ', v_username);
ELSIF UPDATING THEN
INSERT INTO COMPANY_CAR_AUDIT ( REG_NUMBER, MODEL, ASSIGNED_TO_CARERID,
ASSIGNED_DATE, operation, WHO)
VALUES (:NEW.REG_NUMBER,:NEW.MODEL, :NEW.ASSIGNED_TO_CARERID ,
:NEW.ASSIGNED_DATE,
'Update ', v_username);
END IF;
END;
/

Here is the script that will insert into the table


declare
var_result number;
begin
var_result := pkg_tables_creation.cdss_add_company_car('8993 CC 90', 'Toyota
Avensis 2015', null);
if(var_result=0)then
COMMIT;
DBMS_OUTPUT.PUT_LINE('Company car Successfully saved!');
else
DBMS_OUTPUT.PUT_LINE('We are having challenges saving the car at the moment!');
end if;
end;/

After the execution of pkg_tables_createion.cdss_add_company_car, the following was


created automatically by the trigger.

Identification of weaknesses or potential improvements to the


database
The database application program is very robust and easy to use. The package names,
procedures and functions are well defined and are descriptive of what names they are
doing. The CDSS is the acronym for the project, which means Carer Database Scheduling
System.
I started the managerid and carerid from 1000 and interwoven into one another depending
on which id is being created next. This means they use the same trigger to generate id
since they are both employees of a company. This makes it easier to follow. Visit table has
visitid because we are still making use of the id somewhere else within the application
But because of the short period of time, the program however is not short of some
weaknesses including the use of numbers as parameters which might be hard for some
people to remember, Eventhough username in the table for carer and manager are unique
and can be used to search for any for any information just like the carerid and managerid,
I decided to use numbers to uniquely identify the column. The problem with this is that
each carer and manager has to remember their ids and manager has to also remember some
ids in order to get job done within the applicaton.

In the future, the application could be using username instead of ids which is easier to
remember by the carer.
Also, in the future, salary structure could be added to the functionality and feedback after
the visiting has been performed should be part of the application.

Das könnte Ihnen auch gefallen