plsql project enhancement semester 2 teacher
TRANSCRIPT
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
1/32
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
2/32
Oracle Academy 2 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
Sequence:
ASSESSMENT_ID_SEQ
Part 1: Procedures, Functions and Packages
In this section the students start by re-writing the anonymous blocks from MidTerm I to becomeprocedures and functions.
1. Find the file saved from called enroll_student_in_class.sqlfrom MidTerm I. Convert this toa procedure and have it accept a STU_ID and CLASS_ID as inputparameters. Use todays
date for the ENROLLMENT_DATE and the string Enrolled for the STATUS. Raise an
exception if the accepted student is already enrolled in the accepted class. In your exception
handler, display a message stating the student is already enrolled in the class.
Tables used: ENROLLMENTS
Topics Incorporated ==> Scalar variable; %TYPE, Procedure with IN parameters; INSERT;
COMMIT; Exception handling if provided stu_id is already enrolled in providedClass_id. This can be a user-defined exception which is raised after doing a SELECT
which is then followed by an IF statement.
To test, run twice, once to enroll the student and again to test the exception:
BEGIN
enroll_student_in_class(103, 3);END;
Suggested Solution:
--This procedure will enroll a student in a class.CREATE OR REPLACE PROCEDURE enroll_student_in_class
(p_stu_id IN enrollments.stu_id%TYPE,p_class_id IN enrollments.class_id%TYPE)
IS
v_times_enrolled PLS_INTEGER;
e_already_enrolled EXCEPTION;BEGIN
SELECT COUNT(*) INTO v_times_enrolled
FROM enrollments
WHERE class_id = p_class_id
AND stu_id = p_stu_id;IF v_times_enrolled 0
THEN RAISE e_already_enrolled;END IF;
INSERT INTO enrollments
(enrollment_date, class_id, stu_id, status)VALUES
(SYSDATE, p_class_id, p_stu_id, 'Enrolled');
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
3/32
Oracle Academy 3 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
COMMIT;
EXCEPTION
WHEN e_already_enrolled THENDBMS_OUTPUT.PUT_LINE('Student ' || p_stu_id ||
' is already enrolled in class '|| p_class_id);
END enroll_student_in_class;
2. Find the file called drop_student_from_class.sqlfrom MidTerm I. Convert it to a procedurethat accepts a STU_ID and CLASS_ID as input parameters. If the DELETE fails because the
student is not in the class, raise a user_defined exception to display a message stating thestudent is not in the class.
Tables used: ENROLLMENTS
Topics Incorporated ==> %TYPE; Procedure with IN parameters, DELETE;SQL%ROWCOUNT; COMMIT; User-defined exception.
To test, run twice, once to drop the student and again to test the exception:BEGIN
drop_student_from_class(103, 3);
END;
Suggested Solution:
-- This procedure will drop a student from a class.
CREATE OR REPLACE PROCEDURE drop_student_from_class
(p_stu_id IN enrollments.stu_id%TYPE,
p_class_id IN enrollments.class_id%TYPE)IS
e_not_enrolled EXCEPTION;
BEGINDELETE FROM enrollments
WHERE class_id = p_class_id AND stu_id = p_stu_id;
IF SQL%ROWCOUNT = 0 THENRAISE e_not_enrolled;
END IF;
COMMIT;
EXCEPTIONWHEN e_not_enrolled THEN
DBMS_OUTPUT.PUT_LINE('Student ' || p_stu_id ||
' is not enrolled in class '|| p_class_id);
END drop_student_from_class;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
4/32
Oracle Academy 4 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
3. Find the file calledstudent_class_list.sqlfrom MidTerm I. Rewrite it to be a procedure thatdisplays all of the classes a student has been enrolled in within the most recent 10 years. For
example: If you run your procedure on May 10, 2010, you should display all enrollmentsbetween May 10, 2000 and May 10, 2010. Accept the STU_ID as an input parameter. For
each enrollment, display the ENROLLMENT_DATE, CLASS_ID and STATUS.
Tables used: ENROLLMENTSTopics Incorporated ==> %TYPE; Procedure with IN parameters; SYSDATE,
ADD_MONTHS, Explicit cursor to find all courses for the provided Student
ID;DBMS_OUTPUT to display the list of classes.
To test:
BEGIN
student_class_list(101);END;
Suggested Solution:
-- This procedure will list all students in a class.
CREATE OR REPLACE PROCEDURE student_class_list(p_stu_id IN enrollments.stu_id%TYPE)
IS
CURSOR stu_class_cur ISSELECT enrollment_date, class_id, status
FROM enrollments
WHERE stu_id = p_stu_id
AND enrollment_datebetween ADD_MONTHS (SYSDATE,-120) and SYSDATE;
BEGIN
DBMS_OUTPUT.PUT_LINE('Student ' || p_stu_id ||' is enrolled in the following classes:');
FOR stu_class_rec IN stu_class_cur LOOP
DBMS_OUTPUT.PUT_LINE('Class: ' ||stu_class_rec.class_id ||' Enrolled on: ' || stu_class_rec.enrollment_date ||
' and has a status of: '|| stu_class_rec.status );
END LOOP;
END student_class_list;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
5/32
Oracle Academy 5 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
4. Find the file called add_new_classes.sqlfrom MidTerm I. Rewrite it as a Procedure and haveit accept the following IN parameters:
a. number of new classes required. Set a default value of 1.b. Course id; For each new class, use todayas the START_DATE.c. Period, to specify what days the class meets.d.
Frequency, to specify how often it meets.e. Instructor id, to specify who is teaching the class(s).
Note for the teacher:It is probably more likely and safer to use a sequence number for the
class_id. If 2 sessions are calling this procedure at the same time, there is a small chance thesame MAX(class_id) could be found. This would cause the second set of INSERTS to fail.
The first option will work for this project, but you might discuss this interesting subtlety with
your students.
Tables used: CLASSES
Topics Incorporated ==> Creating a procedure; SELECT; INSERT; COMMIT;
DEFAULT value; Using a LOOP to only insert n new rows.
To test:
BEGIN
add_new_classes (2, 1001, 'TUE_TR', 'Once', 3003) ;END;
Suggested Solution 1:
CREATE OR REPLACE PROCEDURE add_new_classes
(p_number_new_classes IN PLS_INTEGER DEFAULT 1,
p_course_id IN classes.course_id%TYPE,p_period IN classes.period%TYPE,
p_frequency IN classes.frequency%TYPE,
p_instr_id IN classes.instr_id%TYPE )IS
v_current_max_class_id classes.class_id%TYPE;
BEGINSELECT MAX(class_id)
INTO v_current_max_class_id
FROM classes;
FOR loop_counter IN 1..p_number_new_classes LOOPINSERT INTO classes (class_id, start_date,course_id,
period, frequency,instr_id)
VALUES (v_current_max_class_id + loop_counter, SYSDATE,
p_course_id, p_period, p_frequency, p_instr_id);COMMIT;
END LOOP;
END add_new_classes;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
6/32
Oracle Academy 6 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
Suggested Solution 2:
SELECT MAX(class_id)
FROM classes;
DROP SEQUENCE class_id_seq;CREATE SEQUENCE class_id_seq
START WITH (number_returned_from_SELECT + 1)
INCREMENT BY 1NOCACHE;
CREATE OR REPLACE PROCEDURE add_new_classes
(p_number_new_classes IN PLS_INTEGER DEFAULT 1,p_course_id IN classes.course_id%TYPE,
p_period IN classes.period%TYPE,
p_frequency IN classes.frequency%TYPE,p_instr_id IN classes.instr_id%TYPE )
IS
BEGIN
FOR loop_counter IN 1..p_number_new_classes LOOPINSERT INTO classes (class_id, start_date,course_id,
period, frequency,instr_id)
VALUES (class_id_seq.NEXTVAL,SYSDATE, p_course_id,p_period,p_frequency,p_instr_id);
COMMIT;
END LOOP;
END add_new_classes;
5. Find the file called course_roster.sqlfrom MidTerm I and rewrite it as a procedure. Acceptthe INSTR_ID and COURSE_ID as input parameters. For each ENROLLMENT, display:
CLASS_ID, STATUS, Student FIRST_NAME and LAST_NAME.
Tables used: ENROLLMENTS; CLASSES; STUDENTS
Topics Incorporated ==> SELECT with JOIN; Explicit Cursor
To test:BEGIN
course_roster(3003, 1002);
END;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
7/32
Oracle Academy 7 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
Suggested Solution:
CREATE OR REPLACE PROCEDURE course_roster(p_instr_id IN classes.instr_id%TYPE,
p_course_id IN classes.course_id%TYPE)
ISCURSOR stu_course_cur ISSELECT e.class_id, e.status, s.first_name, s.last_name
FROM enrollments e, classes c, students s
WHERE e.class_id = c.class_idAND e.stu_id = s.stu_id
AND c.course_id = p_course_id
AND c.instr_id = p_instr_id;
BEGINDBMS_OUTPUT.PUT_LINE('Course ' || p_course_id ||
' has the following students:');
FOR stu_course_rec IN stu_course_cur LOOPDBMS_OUTPUT.PUT_LINE('Class: ' || stu_course_rec.class_id
|| ' Student: '|| stu_course_rec.first_name || ' ' ||
stu_course_rec.last_name ||
' with a status of: ' || stu_course_rec.status );END LOOP;
END course_roster;
6. Find the file called convert_grade.sqlfrom MidTerm I and rewrite it to be a function Use anIN parameter to enter the number grade. RETURN a CHAR value. Use the following rules:
A:90 or above, B: >=80 and=70 and < 80, D: >=60 and < 70, F: Scalar variables...NUMBER IN; CHAR RETURNED; IF or CASEStatement (A=90 to 100, B=80-90, C=70-80, D=60-70, F=
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
8/32
Oracle Academy 8 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
Suggested Solution 1:
CREATE OR REPLACE FUNCTION convert_grade(p_numeric_grade IN NUMBER)
RETURN varchar2
ISv_letter_grade CHAR(1);BEGIN
IF p_numeric_grade >= 90.0 THEN
v_letter_grade := 'A';ELSIF p_numeric_grade >= 80.0 THEN
v_letter_grade := 'B';
ELSIF p_numeric_grade >= 70.0 THEN
v_letter_grade := 'C';ELSIF p_numeric_grade >= 60.0 THEN
v_letter_grade := 'D';
ELSE v_letter_grade := 'F';END IF;
RETURN v_letter_grade;
END convert_grade;
Suggested Solution 2:
CREATE OR REPLACE FUNCTION convert_grade(p_numeric_grade IN NUMBER)
RETURN varchar2
IS
v_letter_grade CHAR(1);BEGIN
v_letter_grade :=
CASE WHEN p_numeric_grade >= 90.0 THEN 'A'WHEN p_numeric_grade >= 80.0 THEN 'B'
WHEN p_numeric_grade >= 70.0 THEN 'C'
WHEN p_numeric_grade >= 60.0 THEN 'D'ELSE 'F'
END;
RETURN v_letter_grade;
END convert_grade;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
9/32
Oracle Academy 9 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
7. Find the file calledstudent_count.sqland rewrite it as a function that will RETURN thenumber of students in a particular class. Accept a CLASS_ID as an IN parameter.
Tables used: ENROLLMENTS
Topics Incorporated ==> Scalar variable...INTEGER; SELECT COUNT(*) INTO variable
FROM enrollments where class_id = ...; using a user-defined function in SQL.
Testing the function:
SELECT class_id, student_count(class_id) AS "Student Count", stu_idFROM enrollments;
Suggested Solution:
CREATE OR REPLACE FUNCTION student_count
(p_class_id IN classes.class_id%TYPE)
RETURN NUMBERIS
v_student_count PLS_INTEGER;
BEGIN
SELECT COUNT(*)INTO v_student_count
FROM enrollments
WHERE class_id = p_class_id;RETURN v_student_count;
END student_count;
8. Create a package called enrollments_packagewhich will contain the procedures you createdin A, B, and C. Make all procedures public. Comment your procedures to explain their
purpose and functionality.
Tables used: ENROLLMENTS
Topics Incorporated ==> Creating a package; incorporating comments.
Suggested Solution:
--PACKAGE SPEC
CREATE OR REPLACE PACKAGE enrollments_packageIS
-- This procedure will enroll a student in a class.
PROCEDURE enroll_student_in_class(p_stu_id IN enrollments.stu_id%TYPE,
p_class_id IN enrollments.class_id%TYPE ) ;
-- This procedure will drop a student from a class
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
10/32
Oracle Academy 10 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
PROCEDURE drop_student_from_class
(p_stu_id IN enrollments.stu_id%TYPE,
p_class_id IN enrollments.class_id%TYPE);-- This procedure will list all students in a class
PROCEDURE student_class_list
(p_stu_id IN enrollments.stu_id%TYPE);END enrollments_package;
--PACKAGE BODY
CREATE OR REPLACE PACKAGE BODY enrollments_package
IS
-- This procedure will enroll a student in a class.
PROCEDURE enroll_student_in_class(p_stu_id IN enrollments.stu_id%TYPE,
p_class_id IN enrollments.class_id%TYPE)
ISv_times_enrolled PLS_INTEGER;
e_already_enrolled EXCEPTION;
BEGIN
SELECT COUNT(*) INTO v_times_enrolledFROM enrollments
WHERE class_id = p_class_id
AND stu_id = p_stu_id;IF v_times_enrolled 0
THEN RAISE e_already_enrolled;
END IF;
INSERT INTO enrollments(enrollment_date, class_id, stu_id, status)
VALUES
(SYSDATE, p_class_id, p_stu_id, 'Enrolled');COMMIT;
EXCEPTION
WHEN e_already_enrolled THENDBMS_OUTPUT.PUT_LINE('Student ' || p_stu_id ||
' is already enrolled in class '|| p_class_id);
END enroll_student_in_class;
-- This procedure will drop a student from a class
PROCEDURE drop_student_from_class
(p_stu_id IN enrollments.stu_id%TYPE,
p_class_id IN enrollments.class_id%TYPE)IS
e_not_enrolled EXCEPTION;
BEGINDELETE FROM enrollments
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
11/32
Oracle Academy 11 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
WHERE class_id = p_class_id AND stu_id = p_stu_id;
IF SQL%ROWCOUNT = 0 THEN RAISE e_not_enrolled; END IF;
COMMIT;EXCEPTION
WHEN e_not_enrolled THEN
DBMS_OUTPUT.PUT_LINE('Student ' || p_stu_id ||' is not enrolled in class '|| p_class_id);END drop_student_from_class;
-- This procedure will list all students in a classPROCEDURE student_class_list
(p_stu_id IN enrollments.stu_id%TYPE)
IS
CURSOR stu_class_cur ISSELECT enrollment_date, class_id, status
FROM enrollments
WHERE stu_id = p_stu_idAND enrollment_date
between ADD_MONTHS (SYSDATE,-120) and SYSDATE;
BEGIN
DBMS_OUTPUT.PUT_LINE('Student ' || p_stu_id ||' is enrolled in the following classes:');
FOR stu_class_rec IN stu_class_cur LOOP
DBMS_OUTPUT.PUT_LINE('Class: ' ||stu_class_rec.class_id || ' Enrolled on: ' ||stu_class_rec.enrollment_date ||
' and has a status of: '|| stu_class_rec.status );
END LOOP;
END student_class_list;
END enrollments_package;
9. Find the program saved in the file create_assignment.sql.Rewrite it as a procedure thataccepts the assignment description as an input parameter.
Tables used: ASSESSMENTS
Topics Incorporated ==> SQL INSERT; IN Argument, Use of sequence in INSERT;
To test:BEGIN
create_assignment('this is to test the procedure');
END;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
12/32
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
13/32
Oracle Academy 13 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
11.Rewrite the program stored in the fileshow_missing_grades.sql to be a procedure. Accept astart_date and end_date to establish a date range. Display only enrollments between those
two dates. Write your procedure so the start_date and end_date are optional. If both dates arenot entered, display all applicable enrollments for the past year, and include a note about the
date range. For each enrollment, list the CLASS_ID, STU_ID, and STATUS. Order the
output by ENROLLMENT_DATE with the most recent enrollments first.
Tables used: ENROLLMENTS
Topics Incorporated ==> SQL with BETWEEN; Dates; Default values with IN parameters,
NULL values in a database column, MONTHS_BETWEEN or other way to find the pastyear.
To test:
BEGINshow_missing_grades('01-AUG-01', '01-AUG-05');
END;
Suggested Solution:
CREATE OR REPLACE PROCEDURE show_missing_grades
(p_start_date IN DATE DEFAULT NULL,p_end_date IN DATE DEFAULT NULL)
IS
CURSOR no_grades_cur ISSELECT class_id, stu_id, status
FROM enrollments
WHERE final_numeric_grade IS NULL
AND final_letter_grade IS NULLAND enrollment_date BETWEEN p_start_date AND
p_end_date
ORDER BY enrollment_date DESC;v_start_date DATE;
v_end_date DATE;
BEGINIF p_start_date IS NULL OR p_end_date IS NULL
THEN
v_start_date := ADD_MONTHS(SYSDATE,-12);
v_end_date := SYSDATE;DBMS_OUTPUT.PUT_LINE
('You have not specified both dates. The listing will
show all enrollments for the past year.');
ELSEv_start_date :=p_start_date;
v_end_date := P_end_date;
END IF;DBMS_OUTPUT.PUT_LINE
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
14/32
Oracle Academy 14 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
('Date range: Between ' || v_start_date || ' and ' ||
v_end_date || '.');
DBMS_OUTPUT.PUT_LINE('The following enrollments have no grade.');
FOR no_grades_rec IN no_grades_cur LOOP
DBMS_OUTPUT.PUT_LINE ('Class ID ' ||no_grades_rec.class_id || 'Student ID ' ||no_grades_rec.stu_id || ' with a status of: '
||no_grades_rec.status);
END LOOP;END show_missing_grades;
12.Find the file called compute_average_grade.sqland rewrite it as a function. Accept aCLASS_ID. Return the average grade.
Tables used: ENROLLMENTSTopics Incorporated ==> SQL with AVG function
To test: (there will be no output since there are no final grades in the table)
DECLAREv_grade NUMBER;
BEGIN
v_grade := compute_average_grade(6);DBMS_OUTPUT.PUT_LINE(v_grade);
END;
Suggested Solution:
CREATE OR REPLACE FUNCTION compute_average_grade
(p_class_id IN enrollments.class_id%TYPE)RETURN NUMBER
IS
v_avg_grade enrollments.final_numeric_grade%TYPE;BEGIN
SELECT AVG(final_numeric_grade)
INTO v_avg_grade
FROM enrollmentsWHERE class_id = p_class_id;
RETURN v_avg_grade;
END compute_average_grade;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
15/32
Oracle Academy 15 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
13.Find the file called count_classes_per_course.sql and rewrite it as a function. Accept aCOURSE_ID. Return the number of classes offered for that course.
Tables used: CLASSES
Topics Incorporated ==> SQL SELECT with COUNT.
To test:
DECLARE
v_classes PLS_INTEGER;BEGIN
v_classes := count_classes_per_course(1001);
DBMS_OUTPUT.PUT_LINE(v_classes);
END;
Suggested Solution:
CREATE OR REPLACE FUNCTION count_classes_per_course
(p_course_id IN classes.course_id%TYPE)
RETURN NUMBER
ISnum_classes PLS_INTEGER;
BEGIN
SELECT COUNT(*)INTO v_num_classes
FROM classes
WHERE course_id = p_course_id;
RETURN v_num_classes;END count_classes_per_course;
14.Convert the fileshow_class_offerings.sql to a procedure. Accept a start date and end date.For each class found, display the CLASS_ID, START_DATE, instructor FIRST_NAME and
LAST_NAME, course TITLE and SECTION_CODE, and average grade. Find the average
grade by a call to the function compute_average_grade.
Tables used: CLASSES, INSTRUCTORS, COURSES,ENROLLMENTS
Topics Incorporated ==> Calling a function from a procedure; using dates; SQL
Join; %TYPE.
To test:
BEGIN
show_class_offerings('01-AUG-01','01-AUG-06');END;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
16/32
Oracle Academy 16 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
Suggested Solution:
CREATE OR REPLACE PROCEDURE show_class_offerings(p_start_date IN DATE,
p_end_date IN DATE)
ISv_avg_grade NUMBER;CURSOR classes_info_cur IS
SELECT cl.class_id, cl.start_date,
i.first_name, i.last_name,cour.title, cour.section_code
FROM classes cl, courses cour, instructors i
WHERE start_date BETWEEN p_start_date AND p_end_date
AND cl.course_id = cour.course_idAND cl.instr_id = i.instructor_id
ORDER BY 1,2,4;
BEGINDBMS_OUTPUT.PUT_LINE
('Date range: Between ' || p_start_date || ' and ' ||
p_end_date || '.');
DBMS_OUTPUT.PUT_LINE('Classes Information.');
FOR classes_info_rec IN classes_info_cur LOOP
-- call the compute_average_grade functionv_avg_grade := compute_average_grade (classes_info_rec.class_id);
DBMS_OUTPUT.PUT_LINE (
'Class ID ' || classes_info_rec.class_id ||
'Average Grade '|| v_avg_grade ||' - Start Date ' || classes_info_rec.start_date ||
'Instructor ' || classes_info_rec.first_name || ' ' || classes_info_rec.last_name ||
'Course Title '|| classes_info_rec.title ||'Offering Section ' || classes_info_rec.section_code );
END LOOP;
END show_class_offerings;
15.Create a package called admin_tools_packageincorporating procedure and functions youwrote in steps K to N. Make the following public:show_missing_grades,
show_class_offerings, count_classes_per_course. Make the following private:compute_average_grade.
Tables used: CLASSES, INSTRUCTORS, COURSES
Topics Incorporated: Creating a package; Public vs. Private package constructs.
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
17/32
Oracle Academy 17 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
--PACKAGE SPEC
CREATE OR REPLACE PACKAGE admin_tools_packageIS
-- This procedure will show missing grades for a class.PROCEDURE show_missing_grades(p_start_date IN DATE DEFAULT ADD_MONTHS(SYSDATE,-12),
p_end_date IN DATE DEFAULT SYSDATE);
-- This procedure will list classes offered
PROCEDURE show_class_offerings
(p_start_date IN DATE,
p_end_date IN DATE);
-- This function will count the number of classes per course.
FUNCTION count_classes_per_course(p_course_id IN classes.course_id%TYPE)
RETURN NUMBER;
END admin_tools_package;
--PACKAGE BODY
CREATE OR REPLACE PACKAGE BODY admin_tools_package
IS
--This function is private in this package and it will compute--the average grade for a class.
FUNCTION compute_average_grade
(p_class_id IN enrollments.class_id%TYPE)RETURN NUMBER
IS
v_avg_grade enrollments.final_numeric_grade%TYPE;BEGIN
SELECT AVG(final_numeric_grade)
INTO v_avg_grade
FROM enrollmentsWHERE class_id = p_class_id;
RETURN v_avg_grade;
END compute_average_grade;
--This procedure will show missing grades for a class.
--------------------------------------------------------
PROCEDURE show_missing_grades(p_start_date IN DATE DEFAULT ADD_MONTHS(SYSDATE,-12),
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
18/32
Oracle Academy 18 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
p_end_date IN DATE DEFAULT SYSDATE)
IS
CURSOR no_grades_cur ISSELECT class_id, stu_id, status
FROM enrollments
WHERE final_numeric_grade IS NULLAND final_letter_grade IS NULLAND enrollment_date BETWEEN p_start_date AND
p_end_date
ORDER BY enrollment_date DESC;BEGIN
IF p_start_date IS NULL OR p_end_date IS NULL
THEN
DBMS_OUTPUT.PUT_LINE('You have not specified both dates. The listing will show all enrollments for the past
year.');
END IF;DBMS_OUTPUT.PUT_LINE
('Date range: Between ' || p_start_date || ' and ' || p_end_date || '.');
DBMS_OUTPUT.PUT_LINE
('The following enrollments have no grade.');FOR no_grades_rec IN no_grades_cur LOOP
DBMS_OUTPUT.PUT_LINE ('Class ID ' || no_grades_rec.class_id || 'Student ID ' ||
no_grades_rec.stu_id || ' with a status of: ' ||no_grades_rec.status);END LOOP;
END show_missing_grades;
--This procedure will list classes offered--------------------------------
PROCEDURE show_class_offerings
(p_start_date IN DATE,p_end_date IN DATE)
ISv_avg_grade NUMBER;
CURSOR classes_info_cur IS
SELECT cl.class_id, cl.start_date,
i.first_name, i.last_name,cour.title, cour.section_code
FROM classes cl, courses cour, instructors i
WHERE start_date BETWEEN p_start_date and p_end_date
AND cl.course_id = cour.course_idAND cl.instr_id = i.instructor_id
ORDER BY 1,2,4;
--BEGIN
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
19/32
Oracle Academy 19 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
DBMS_OUTPUT.PUT_LINE
('Date range: Between ' || p_start_date || ' and ' || p_end_date || '.');
DBMS_OUTPUT.PUT_LINE('Classes Information.');
FOR classes_info_rec IN classes_info_cur LOOP
v_avg_grade := compute_average_grade(classes_info_rec.class_id);DBMS_OUTPUT.PUT_LINE (
'Class ID ' || classes_info_rec.class_id ||
'Average Grade '|| v_avg_grade ||' - Start Date ' || classes_info_rec.start_date ||
'Instructor ' || classes_info_rec.first_name || ' ' ||
classes_info_rec.last_name ||
'Course Title '|| classes_info_rec.title ||'Offering Section ' || classes_info_rec.section_code );
END LOOP;
END show_class_offerings;
--This function will count the number of classes per course.
------------------------------------------------------
FUNCTION count_classes_per_course(p_course_id IN classes.course_id%TYPE)
RETURN NUMBER
ISv_num_classes PLS_INTEGER;
BEGIN
SELECT COUNT(*)
INTO v_num_classesFROM classes
WHERE course_id = p_course_id;
RETURN v_num_classes;END count_classes_per_course;
END admin_tools_package;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
20/32
Oracle Academy 20 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
Part 2: Managing Students and Grades (enrollments_package)
The enrollments_packageyou created in Part 1 contains the following public procedures:
1. Procedure enroll_student_in_class(p_stu_id IN enrollments.stu_id%TYPE, p_class_id INenrollments.class_id%TYPE)
2. Procedure drop_student_from_class(p_stu_id IN enrollments.stu_id%TYPE, p_class_id INenrollments.class_id%TYPE)
3. Procedurestudent_class_list(p_stu_id IN enrollments.stu_id%TYPE)
The Assignment and Deliverables:Modify thestudent_class_list procedure in the package, to add the following functionality:
1. Utilize the overloading feature of the PLSQL package, to overload thestudent_class_listprocedure as follows:
When the STU_ID parameter is passed, the procedure should display a list of classes inwhich the student has been enrolled, within the most recent 6 years.
When the procedure is called without a parameter, the procedure should display a list ofclasses for all students in which they have been enrolled, within the most recent 6 years.
2. Create a procedure read_external_file, to read an external text file stored outside the databaseas an operating system text file. Use DBMS_OUTPUT to display the content of the external
file.
The external file is named student_class_list.txtand is stored in the operating system
directory referenced by the Oracle directory object 'WF_FLAGS'.
Your output should look something like this:
Enrollment Report
Student Id Enrollment Date Class id101 12-AUG-04 1
102 12-AUG-04 1
103 12-AUG-04 1104 12-AUG-04 1
*** END OF REPORT ***
Hints: The Exceptions used with UTL_FILE.GET_LINE: INVALID_FILEHANDLE INVALID_OPERATION READ_ERROR NO_DATA_FOUND VALUE_ERROR
Directory object name is: 'WF_FLAGS' and must be referenced in capital letters.
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
21/32
Oracle Academy 21 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
Incorporated Topics for problems 1 and 2:
Overloading procedures in a package. Reading external files with the UTL_FILE package. Students must use a Directory object WF_FLAGS that is part of the standard course setup.
Oracle Directory names are case sensitive, so the students must type it in exactly as above.
Oracle Corporation security rules do allow Academy participants to read but not createexternal text files (using UTL_FILE) on database server machines. This is why the text filestudent_class_list.txt is provided for you.
To test:
BEGIN
enrollments_package.read_external_file;
END;
Part 2: Suggested Solution
--PACKAGE SPEC
CREATE OR REPLACE PACKAGE enrollments_packageIS
-- This procedure will enroll a student in a class.PROCEDURE enroll_student_in_class
(p_stu_id IN enrollments.stu_id%TYPE,p_class_id IN enrollments.class_id%TYPE ) ;
-- This procedure will drop a student from a class
PROCEDURE drop_student_from_class(p_stu_id IN enrollments.stu_id%TYPE,
p_class_id IN enrollments.class_id%TYPE);
-- Overloaded procedure will list Enrollment date and class ids for a student
PROCEDURE student_class_list(p_stu_id IN enrollments.stu_id%TYPE);
-- Overloaded procedure will list Enrollment date and class ids for all students
PROCEDURE student_class_list;
PROCEDURE read_external_file;
END enrollments_package;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
22/32
Oracle Academy 22 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
--PACKAGE BODY
CREATE OR REPLACE PACKAGE BODY enrollments_packageIS
-- This procedure will enroll a student in a class.
PROCEDURE enroll_student_in_class
(p_stu_id IN enrollments.stu_id%TYPE,
p_class_id IN enrollments.class_id%TYPE)IS
v_times_enrolled PLS_INTEGER;
e_already_enrolled EXCEPTION;
BEGINSELECT COUNT(*) INTO v_times_enrolled
FROM enrollments
WHERE class_id = p_class_idAND stu_id = p_stu_id;
IF v_times_enrolled 0
THEN RAISE e_already_enrolled;END IF;
INSERT INTO enrollments (enrollment_date, class_id, stu_id,status)
VALUES( SYSDATE, p_class_id, p_stu_id, 'Enrolled');
COMMIT;
EXCEPTIONWHEN e_already_enrolled THEN
DBMS_OUTPUT.PUT_LINE('Student ' || p_stu_id ||
' is already enrolled in class '|| p_class_id);END enroll_student_in_class;
-- This procedure will drop a student from a class
PROCEDURE drop_student_from_class
(p_stu_id IN enrollments.stu_id%TYPE,
p_class_id IN enrollments.class_id%TYPE)IS
e_not_enrolled EXCEPTION;
BEGIN
DELETE FROM enrollmentsWHERE class_id = p_class_id AND stu_id = p_stu_id;
IF SQL%ROWCOUNT = 0 THEN RAISE e_not_enrolled; END IF;
COMMIT;EXCEPTION
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
23/32
Oracle Academy 23 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
WHEN e_not_enrolled THEN
DBMS_OUTPUT.PUT_LINE('Student ' || p_stu_id ||' is not enrolled in class '|| p_class_id);
END drop_student_from_class;
-- This procedure will list a students enrollments
-- Overloaded procedure with one parameter
PROCEDURE student_class_list
(p_stu_id IN enrollments.stu_id%TYPE)
ISCURSOR stu_class_cur IS
SELECT enrollment_date, class_id, status
FROM enrollments
WHERE stu_id = p_stu_idAND enrollment_date
BETWEEN ADD_MONTHS (SYSDATE,-72) and SYSDATE;
BEGINDBMS_OUTPUT.PUT_LINE('Student ' || p_stu_id ||
' is enrolled in the following classes:');
FOR stu_class_rec IN stu_class_cur LOOP
DBMS_OUTPUT.PUT_LINE('Class: ' ||stu_class_rec.class_id || ' Enrolled on: ' ||stu_class_rec.enrollment_date ||
' and has a status of: '|| stu_class_rec.status );
END LOOP;END student_class_list;
-- This procedure will list all students
-- Overloaded procedure with no parameter
PROCEDURE student_class_list
IS
CURSOR stu_class_cur IS
SELECT enrollment_date, class_id, status, stu_idFROM enrollments
WHERE enrollment_date
BETWEEN ADD_MONTHS (SYSDATE,-72) and SYSDATE
ORDER BY stu_id, enrollment_date ,class_id;
BEGIN
DBMS_OUTPUT.PUT_LINE('Students are enrolled in the following classes:');
FOR stu_class_rec IN stu_class_cur LOOPDBMS_OUTPUT.PUT_LINE('Student: ' || stu_class_rec.stu_id || ' Class: '
||stu_class_rec.class_id || ' Enrolled on: ' || stu_class_rec.enrollment_date ||
' and has a status of: '|| stu_class_rec.status );END LOOP;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
24/32
Oracle Academy 24 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
END student_class_list;
--Procedure read_external_file to read and display an external operating system text file.--
PROCEDURE read_external_file
ISfile UTL_FILE.FILE_TYPE;v_line varchar2(1024);
BEGIN--the number of bytes returned will be 1024 or less if a line terminator is seen.
file := UTL_FILE.FOPEN ('WF_FLAGS', 'student_class_list.txt', 'r');
-- Nested Block to handle end of file errors locally.
BEGINLOOP
UTL_FILE.GET_LINE(file , v_line);
DBMS_OUTPUT.PUT_LINE( v_line );END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;END;
EXCEPTION
--If no text was read due to end of file, the NO_DATA_FOUND exception is raisedWHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20005, 'END OF FILE.');
WHEN UTL_FILE.INVALID_FILEHANDLE THENRAISE_APPLICATION_ERROR(-20006,'Invalid File.');
WHEN UTL_FILE.INVALID_OPERATION THENRAISE_APPLICATION_ERROR (-20007, 'Unable to read or operate as requested.');
WHEN UTL_FILE.READ_ERROR THENRAISE_APPLICATION_ERROR (-20008, 'Unable to read the file.');
END read_external_file;
END enrollments_package;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
25/32
Oracle Academy 25 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
Part 3: School Administrators Tools (admin_tools_package)
The admin_tools_packageyou created in Part I contains the following programs:
1. Procedureshow_missing_grades(p_start_date IN DATE DEFAULT NULL,p_end_date IN DATE DEFAULT NULL)2. Procedureshow_class_offerings (p_start_date IN DATE, p_end_date IN DATE)3. Function count_classes_per_course (p_course_id IN classes.course_id%TYPE) RETURN
NUMBER
4. Function compute_average_grade (p_class_id IN enrollments.class_id%TYPE) RETURNNUMBER
This function is private in this package.
The Assignment and Deliverables:
1. Utilize the forward declaration concept to be able to move the body of the private functioncompute_average_gradeto anywhere in the package body. Recompile and test the package.To test:
BEGIN
admin_tools_package.show_class_offerings('01-AUG-01','01-AUG-06');
END;
Part 3: Suggested Solution
--PACKAGE SPEC
CREATE OR REPLACE PACKAGE admin_tools_package
IS
-- This procedure will show missing grades for a class.
PROCEDURE show_missing_grades(p_start_date IN DATE DEFAULT NULL,p_end_date IN DATE DEFAULT NULL);
-- This procedure will list classes offeredPROCEDURE show_class_offerings
(p_start_date IN DATE,p_end_date IN DATE);
-- This function will count the number of classes per course.
FUNCTION count_classes_per_course
(p_course_id IN classes.course_id%TYPE)RETURN NUMBER;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
26/32
Oracle Academy 26 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
END admin_tools_package;
--PACKAGE BODY
CREATE OR REPLACE PACKAGE BODY admin_tools_package
IS
--This function is private in this package and it will compute
--The average grade for a class.
--Forward Declaration
FUNCTION compute_average_grade (p_class_id IN enrollments.class_id%TYPE)
RETURN NUMBER;
--This procedure will show missing grades for a class.
----------------------------------------------------
PROCEDURE show_missing_grades(p_start_date IN DATE DEFAULT NULL,
p_end_date IN DATE DEFAULT NULL)
IS
CURSOR no_grades_cur ISSELECT class_id, stu_id, status
FROM enrollments
WHERE final_numeric_grade IS NULLAND final_letter_grade IS NULL
AND enrollment_date BETWEEN p_start_date AND
p_end_date
ORDER BY enrollment_date DESC;v_start_date DATE;
v_end_date DATE;
BEGINIF p_start_date IS NULL OR p_end_date IS NULL
THEN
v_start_date := ADD_MONTHS(SYSDATE,-12);v_end_date := SYSDATE;
DBMS_OUTPUT.PUT_LINE
('You have not specified both dates. The listing will
show all enrollments for the past year.');ELSE
v_start_date :=p_start_date;
v_end_date := P_end_date;
END IF;DBMS_OUTPUT.PUT_LINE
('Date range: Between ' || v_start_date || ' and ' ||
v_end_date || '.');DBMS_OUTPUT.PUT_LINE
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
27/32
Oracle Academy 27 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
('The following enrollments have no grade.');
FOR no_grades_rec IN no_grades_cur LOOP
DBMS_OUTPUT.PUT_LINE ('Class ID ' ||no_grades_rec.class_id || 'Student ID ' ||
no_grades_rec.stu_id || ' with a status of: '
||no_grades_rec.status);END LOOP;END show_missing_grades;
--This procedure will list classes offered----------------------------------
PROCEDURE show_class_offerings
(p_start_date IN DATE,
p_end_date IN DATE)
IS
v_avg_grade NUMBER;CURSOR classes_info_cur IS
SELECT cl.class_id, cl.start_date,
i.first_name, i.last_name,
cour.title, cour.section_codeFROM classes cl, courses cour, instructors i
WHERE start_date BETWEEN p_start_date AND p_end_date
AND cl.course_id = cour.course_idAND cl.instr_id = i.instructor_id
ORDER BY 1,2,4;
--
BEGINDBMS_OUTPUT.PUT_LINE
('Date range: Between ' || p_start_date || ' AND ' || p_end_date || '.');
DBMS_OUTPUT.PUT_LINE ('Classes Information.');
FOR classes_info_rec IN classes_info_cur LOOP
v_avg_grade := compute_average_grade (classes_info_rec.class_id);DBMS_OUTPUT.PUT_LINE (
'Class ID ' || classes_info_rec.class_id ||
'Average Grade '|| v_avg_grade ||
' - Start Date ' || classes_info_rec.start_date ||'Intructor ' || classes_info_rec.first_name || ' ' ||
classes_info_rec.last_name ||
'Course Title '|| classes_info_rec.title ||
'Offering Section ' || classes_info_rec.section_code );END LOOP;
END show_class_offerings;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
28/32
Oracle Academy 28 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
--This function will count the number of classes per course.
FUNCTION count_classes_per_course(p_course_id IN classes.course_id%TYPE)
RETURN NUMBER
ISv_num_classes PLS_INTEGER;BEGIN
SELECT COUNT(*)
INTO v_num_classesFROM classes
WHERE course_id = p_course_id;
RETURN v_num_classes;
END count_classes_per_course;
FUNCTION compute_average_grade
(p_class_id IN enrollments.class_id%TYPE)RETURN NUMBER
IS
v_avg_grade enrollments.final_numeric_grade%TYPE;
BEGINSELECT AVG(final_numeric_grade)
INTO v_avg_grade
FROM enrollmentsWHERE class_id = p_class_id;
RETURN v_avg_grade;
END compute_average_grade;
END admin_tools_package;
Part 4: Create Database Triggers
1. Create thegrade_change_historytable as follows:CREATE TABLE grade_change_history
(time_stamp DATE,
stu_id NUMBER(7,0),
class_id NUMBER(6,0),
enroll_date DATE,old_final_grade CHAR(1),
new_final_grade CHAR(1));
2. Create a row level trigger audit_grade_changeto keep a history of all the changes made tostudents final letter grade. The grade change is recorded every time theFINAL_LETTER_GRADE field is updated in the ENROLLMENTS table.
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
29/32
Oracle Academy 29 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
Every time the trigger is fired, it should insert a record in theGRADE_CHANGE_HISTORY table, recording the old grade and the new grade for each
student.
Test your trigger by updating the final_letter_grade for a student, in theENROLLMENTS table.
Topics Incorporated: Row level DML triggerTables Used: ENROLLMENTS, GRADE_CHANGE_HISTORY
To test:1. UPDATE enrollments
SET final_letter_grade = 'A'
WHERE stu_id = 101;
2. SELECT * FROM grade_change_history;
Part 4: Suggested Solution
--Trigger Code
------------------
CREATE OR REPLACE TRIGGER audit_grade_change
AFTER UPDATE OF final_letter_grade ON enrollments
FOR EACH ROW
BEGININSERT INTO grade_change_history(time_stamp,stu_id, class_id,enroll_date, old_final_grade, new_final_grade)
VALUES(SYSDATE,
:OLD.stu_id,:OLD.class_id,
:OLD.enrollment_date,
:OLD.final_letter_grade,
:NEW.final_letter_grade);END;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
30/32
Oracle Academy 30 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
Part 5: Create manage_triggers_package
The Assignment and Deliverables:
1. Create a package manage_triggers_package that contains two overloaded functions calledmanage_triggers. The functions are invoked to disable/enable all triggers for a table, or tocompile a trigger.
Use Native Dynamic SQL to execute the DDL commands programmatically. Code an exception handling block to display a message if the DDL command fails.Use the following guidelines:
When the function is called with two parameters: manage_triggers (p_tablename,p_action)
Pass a table name to P_TABLENAME parameter. Pass disable or enable string to P_ACTION parameter.
When the function is called with only one parameter manage_triggers (p_trigger_name) Pass a trigger name to P_TRIGGER_NAME parameter.
Hints:
Use the ALTER TABLE command to disable/enable all triggers of a tableprogrammatically.
Use the ALTER TRIGGER command to compile the trigger programmatically.Topics Incorporated: Forward Declaration, Native Dynamic SQL, Overloading, exception
handling.
Tables used: CLASSES, INSTRUCTORS, COURSES
To test: -Pass a table name to P_TABLENAME parameter
-Pass disable or enable string to P_ACTION parameter.
-Pass a trigger name to P_TRIGGER_NAME parameter.
BEGIN
manage_triggers_package.manage_triggers('ENROLLMENTS', 'ENABLE');
END;
BEGIN
manage_triggers_package.manage_triggers('audit_grade_change');END;
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
31/32
Oracle Academy 31 Database Programming with PL/SQL
Copyright 2010, Oracle. All rights reserved.
Part 5: Suggested Solution
--Create a new package to manage the database triggers.
--PACKAGE SPEC
CREATE OR REPLACE PACKAGE manage_triggers_packageIS
PROCEDURE manage_triggers(p_tablename IN VARCHAR2, p_mode IN
VARCHAR2);
PROCEDURE manage_triggers(p_trigger_name IN VARCHAR2);
END manage_triggers_package;
--PACKAGE BODY
CREATE OR REPLACE PACKAGE BODY manage_triggers_package
IS
--Overloaded Procedure manage triggers------------------------------
PROCEDURE manage_triggers(p_tablename IN VARCHAR2, p_mode IN
VARCHAR2)IS
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE '||p_tablename||' '|| p_mode || ' All TRIGGERS';
DBMS_OUTPUT.PUT_LINE(p_tablename || ' Altered.');
EXCEPTION
WHEN OTHERS THENRAISE_APPLICATION_ERROR(-20001,'DDL Command Failed.');
END;
--Overloaded Procedure manage triggers
------------------------------
PROCEDURE manage_triggers(p_trigger_name IN VARCHAR2)
ISBEGIN
EXECUTE IMMEDIATE 'ALTER TRIGGER '||p_trigger_name|| '
COMPILE';
DBMS_OUTPUT.PUT_LINE(p_trigger_name|| ' Trigger Compiled. ');
EXCEPTIONWHEN OTHERS THEN
-
8/13/2019 PLSQL Project Enhancement Semester 2 Teacher
32/32
RAISE_APPLICATION_ERROR(-20001,'DDL Command Failed.');
END;
END manage_triggers_package;