MidTerm Project Part II Instructions for Instructors

The midterm project is divided into 5 parts. You can use the 5 parts in various ways depending on how much time you wish to devote to this project or on the technical level of your students.   All 5 parts can be assigned to individual students. There are dependencies between the parts, so 1 must be completed before 2 and 3; 4 must be completed before 5. The class can be divided into teams and the teams can complete all 5 parts. There are dependencies between the parts, so 1 must be completed before 2 and 3; 4 must be completed before 5.

The code for two packages enrollments_package and admin_tools_package must be created from the anonymous blocks your students wrote in the first MidTerm Project. If these files are lost, there were suggested solutions in the teacher document for Part I; you can use these solutions to re-create the programs. You are instructed to modify the existing programs from Part I, to incorporate the required topics for this project. The students are also required to create a new package manage_triggers_package to disable/enable triggers for a table or to compile a specific trigger.

Project setup: The Data
This project will build on the case study called STUDENT ADMINISTRATION or SA. A set of database tables is used to manage schools‟ course offerings as delivered by instructors in many classes over time. Information is stored about classes that are offered, the students who take classes, and the grades the students receive on various assessments. The school administrators can use the SA database to manage the class offerings and to assign instructors. Teachers can also use the SA database to track student performance. The database objects for this project are already in the students‟ accounts and they are as follows: Tables: INSTRUCTORS SECTIONS COURSES CLASSES ASSESSMENTS STUDENTS ENROLLMENTS CLASS_ASSESSMENTS ERROR_LOG GRADE_CHANGES

Oracle Academy

1 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 become procedures and functions. 1. Find the file saved from called enroll_student_in_class.sql from MidTerm I. Convert this to a procedure and have it accept a STU_ID and CLASS_ID as input parameters. Use “today‟s 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 provided Class_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'); Oracle Academy 2 Database Programming with PL/SQL Copyright © 2010, Oracle. All rights reserved.

COMMIT; EXCEPTION WHEN 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; 2. Find the file called drop_student_from_class.sql from MidTerm I. Convert it to a procedure that 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 the student 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; BEGIN DELETE FROM enrollments 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;

Oracle Academy

3 Database Programming with PL/SQL Copyright © 2010, Oracle. All rights reserved.

Accept the STU_ID as an input parameter.stu_id%TYPE) IS CURSOR stu_class_cur IS SELECT enrollment_date. CREATE OR REPLACE PROCEDURE student_class_list (p_stu_id IN enrollments.PUT_LINE('Class: ' ||stu_class_rec.DBMS_OUTPUT to display the list of classes. Tables used: ENROLLMENTS Topics Incorporated ==> %TYPE. 2010. status FROM enrollments WHERE stu_id = p_stu_id AND enrollment_date between ADD_MONTHS (SYSDATE. class_id.PUT_LINE('Student ' || p_stu_id || ' is enrolled in the following classes:'). All rights reserved. FOR stu_class_rec IN stu_class_cur LOOP DBMS_OUTPUT. To test: BEGIN student_class_list(101). Explicit cursor to find all courses for the provided Student ID.enrollment_date || ' and has a status of: '|| stu_class_rec. For each enrollment.-120) and SYSDATE. Oracle. 2000 and May 10. For example: If you run your procedure on May 10. BEGIN DBMS_OUTPUT.status ). Rewrite it to be a procedure that displays all of the classes a student has been enrolled in within the most recent 10 years.class_id || ' Enrolled on: ' || stu_class_rec. Procedure with IN parameters.3. END student_class_list. Find the file called student_class_list. 2010. CLASS_ID and STATUS. . you should display all enrollments between May 10. SYSDATE. Suggested Solution: -. END LOOP. END. ADD_MONTHS.sql from MidTerm I. display the ENROLLMENT_DATE.This procedure will list all students in a class. Oracle Academy 4 Database Programming with PL/SQL Copyright © 2010.

instr_id) VALUES (v_current_max_class_id + loop_counter. END LOOP. Oracle. d. there is a small chance the same MAX(class_id) could be found.sql from MidTerm I. period. to specify how often it meets. If 2 sessions are calling this procedure at the same time. start_date. Tables used: CLASSES Topics Incorporated ==> Creating a procedure. . number of new classes required. Using a LOOP to only insert “n” new rows. Note for the teacher: It is probably more likely and safer to use a sequence number for the class_id. Find the file called add_new_classes.course_id. p_period. Set a default value of 1.period%TYPE. All rights reserved. Frequency.class_id%TYPE. to specify who is teaching the class(s). 'Once'. use “today”as the START_DATE. p_instr_id IN classes. Oracle Academy 5 Database Programming with PL/SQL Copyright © 2010. BEGIN SELECT MAX(class_id) INTO v_current_max_class_id FROM classes. p_instr_id). p_frequency. Suggested Solution 1: CREATE OR REPLACE PROCEDURE add_new_classes (p_number_new_classes IN PLS_INTEGER DEFAULT 1. e. Period.frequency%TYPE. DEFAULT value. END add_new_classes. p_period IN classes. SYSDATE..course_id%TYPE. to specify what days the class meets. Course id. COMMIT. This would cause the second set of INSERTS to fail. The first option will work for this project. p_frequency IN classes. 'TUE_TR'. INSERT. 1001. SELECT. p_course_id IN classes. p_course_id. Instructor id. b. c. To test: BEGIN add_new_classes (2.instr_id%TYPE ) IS v_current_max_class_id classes. COMMIT. 3003) .p_number_new_classes LOOP INSERT INTO classes (class_id. frequency. Rewrite it as a Procedure and have it accept the following IN parameters: a. but you might discuss this interesting subtlety with your students.4. For each new class. END. FOR loop_counter IN 1.

instr_id) VALUES (class_id_seq. Student FIRST_NAME and LAST_NAME.Suggested Solution 2: SELECT MAX(class_id) FROM classes. STUDENTS Topics Incorporated ==> SELECT with JOIN. Accept the INSTR_ID and COURSE_ID as input parameters.p_instr_id). p_period IN classes. All rights reserved. Oracle. END add_new_classes. Oracle Academy 6 Database Programming with PL/SQL Copyright © 2010. DROP SEQUENCE class_id_seq.NEXTVAL. display: CLASS_ID. p_frequency IN classes. frequency.frequency%TYPE. 5. For each ENROLLMENT.SYSDATE.course_id%TYPE. CLASSES. COMMIT. . 1002). END LOOP.period%TYPE. p_course_id. period. Find the file called course_roster.sql from MidTerm I and rewrite it as a procedure..course_id. start_date. p_course_id IN classes. Explicit Cursor To test: BEGIN course_roster(3003. p_instr_id IN classes.instr_id%TYPE ) IS BEGIN FOR loop_counter IN 1.p_frequency. STATUS. END. p_period.p_number_new_classes LOOP INSERT INTO classes (class_id. CREATE OR REPLACE PROCEDURE add_new_classes (p_number_new_classes IN PLS_INTEGER DEFAULT 1. Tables used: ENROLLMENTS. CREATE SEQUENCE class_id_seq START WITH (number_returned_from_SELECT + 1) INCREMENT BY 1 NOCACHE.

s. D: >=60 and < 70. To Test: BEGIN DBMS_OUTPUT.stu_id = s.NUMBER IN.first_name || ' ' || stu_course_rec.first_name.class_id = c.. B: >=80 and<90 . D=60-70. C=70-80. Use the following rules: A:90 or above. classes c. students s WHERE e. END.status ). B=80-90.instr_id = p_instr_id. 6.last_name FROM enrollments e. Find the file called convert_grade. All rights reserved.instr_id%TYPE.Should return 'A'. C: >=70 and < 80.Suggested Solution: CREATE OR REPLACE PROCEDURE course_roster (p_instr_id IN classes.course_id = p_course_id AND c. END LOOP. CHAR RETURNED. .. s.status.stu_id AND c. Oracle. Tables used: None Topics Incorporated ==> Scalar variables. FOR stu_course_rec IN stu_course_cur LOOP DBMS_OUTPUT.class_id || ' Student: '|| stu_course_rec.sql from MidTerm I and rewrite it to be a function Use an IN parameter to enter the number grade. Oracle Academy 7 Database Programming with PL/SQL Copyright © 2010. IF or CASE Statement (A=90 to 100.PUT_LINE('Class: ' || stu_course_rec.class_id AND e.course_id%TYPE) IS CURSOR stu_course_cur IS SELECT e.class_id. e.PUT_LINE(convert_grade (92)). BEGIN DBMS_OUTPUT. RETURN a CHAR value. F=<60. -.last_name || ' with a status of: ' || stu_course_rec.PUT_LINE('Course ' || p_course_id || ' has the following students:'). p_course_id IN classes. END course_roster. F:<60.

0 THEN v_letter_grade := 'C'. END convert_grade. END convert_grade. Oracle.0 THEN 'A' WHEN p_numeric_grade >= 80. BEGIN IF p_numeric_grade >= 90. RETURN v_letter_grade. ELSIF p_numeric_grade >= 60.0 THEN v_letter_grade := 'A'. ELSIF p_numeric_grade >= 80. Oracle Academy 8 Database Programming with PL/SQL Copyright © 2010. BEGIN v_letter_grade := CASE WHEN p_numeric_grade >= 90. Suggested Solution 2: CREATE OR REPLACE FUNCTION convert_grade (p_numeric_grade IN NUMBER) RETURN varchar2 IS v_letter_grade CHAR(1). ELSE v_letter_grade := 'F'.0 THEN 'B' WHEN p_numeric_grade >= 70. All rights reserved. ELSIF p_numeric_grade >= 70.0 THEN 'C' WHEN p_numeric_grade >= 60.0 THEN v_letter_grade := 'D'. END IF. RETURN v_letter_grade.0 THEN 'D' ELSE 'F' END.0 THEN v_letter_grade := 'B'. .Suggested Solution 1: CREATE OR REPLACE FUNCTION convert_grade (p_numeric_grade IN NUMBER) RETURN varchar2 IS v_letter_grade CHAR(1).

incorporating comments.. Create a package called enrollments_package which will contain the procedures you created in A.stu_id%TYPE. .. Suggested Solution: --PACKAGE SPEC CREATE OR REPLACE PACKAGE enrollments_package IS -. Make all procedures public. BEGIN SELECT COUNT(*) INTO v_student_count FROM enrollments WHERE class_id = p_class_id. RETURN v_student_count. Tables used: ENROLLMENTS Topics Incorporated ==> Creating a package. Suggested Solution: CREATE OR REPLACE FUNCTION student_count (p_class_id IN classes. -.sql and rewrite it as a function that will RETURN the number of students in a particular class.This procedure will enroll a student in a class. stu_id FROM enrollments. student_count(class_id) AS "Student Count". Tables used: ENROLLMENTS Topics Incorporated ==> Scalar variable.class_id%TYPE ) .This procedure will drop a student from a class Oracle Academy 9 Database Programming with PL/SQL Copyright © 2010. PROCEDURE enroll_student_in_class (p_stu_id IN enrollments.class_id%TYPE) RETURN NUMBER IS v_student_count PLS_INTEGER. B.. Accept a CLASS_ID as an IN parameter.. Find the file called student_count. p_class_id IN enrollments. and C. 8. All rights reserved.7. END student_count. Testing the function: SELECT class_id. Comment your procedures to explain their purpose and functionality. Oracle.INTEGER. using a user-defined function in SQL.. SELECT COUNT(*) INTO variable FROM enrollments where class_id = .

stu_id%TYPE. END enrollments_package. p_class_id. p_class_id IN enrollments. e_already_enrolled EXCEPTION. EXCEPTION WHEN e_already_enrolled THEN DBMS_OUTPUT. -. p_class_id IN enrollments. All rights reserved.stu_id%TYPE.This procedure will enroll a student in a class. class_id. p_stu_id. --PACKAGE BODY CREATE OR REPLACE PACKAGE BODY enrollments_package IS -.PUT_LINE('Student ' || p_stu_id || ' is already enrolled in class '|| p_class_id). BEGIN SELECT COUNT(*) INTO v_times_enrolled FROM enrollments WHERE class_id = p_class_id AND stu_id = p_stu_id.stu_id%TYPE. COMMIT. IF v_times_enrolled <> 0 THEN RAISE e_already_enrolled. Oracle. status) VALUES (SYSDATE. .stu_id%TYPE). PROCEDURE enroll_student_in_class (p_stu_id IN enrollments. stu_id.PROCEDURE drop_student_from_class (p_stu_id IN enrollments. INSERT INTO enrollments (enrollment_date.This procedure will drop a student from a class PROCEDURE drop_student_from_class (p_stu_id IN enrollments. 'Enrolled'). p_class_id IN enrollments. -.class_id%TYPE) IS e_not_enrolled EXCEPTION.class_id%TYPE). END IF.class_id%TYPE) IS v_times_enrolled PLS_INTEGER.This procedure will list all students in a class PROCEDURE student_class_list (p_stu_id IN enrollments. BEGIN DELETE FROM enrollments Oracle Academy 10 Database Programming with PL/SQL Copyright © 2010. END enroll_student_in_class.

Find the program saved in the file create_assignment.class_id || ' Enrolled on: ' || stu_class_rec. class_id.This procedure will list all students in a class PROCEDURE student_class_list (p_stu_id IN enrollments. Rewrite it as a procedure that accepts the assignment description as an input parameter. END drop_student_from_class.status ). END enrollments_package.stu_id%TYPE) IS CURSOR stu_class_cur IS SELECT enrollment_date. To test: BEGIN create_assignment('this is to test the procedure').PUT_LINE('Student ' || p_stu_id || ' is not enrolled in class '|| p_class_id). IN Argument.sql. END LOOP. status FROM enrollments WHERE stu_id = p_stu_id AND enrollment_date between ADD_MONTHS (SYSDATE. -.enrollment_date || ' and has a status of: '|| stu_class_rec. . Use of sequence in INSERT. All rights reserved. COMMIT. FOR stu_class_rec IN stu_class_cur LOOP DBMS_OUTPUT.PUT_LINE('Student ' || p_stu_id || ' is enrolled in the following classes:').PUT_LINE('Class: ' ||stu_class_rec.WHERE class_id = p_class_id AND stu_id = p_stu_id. BEGIN DBMS_OUTPUT. Tables used: ASSESSMENTS Topics Incorporated ==> SQL INSERT. EXCEPTION WHEN e_not_enrolled THEN DBMS_OUTPUT. 9. Oracle Academy 11 Database Programming with PL/SQL Copyright © 2010. IF SQL%ROWCOUNT = 0 THEN RAISE e_not_enrolled. Oracle. END IF.-120) and SYSDATE. END. END student_class_list.

87.1). date_turned_in. p_class_id IN class_assessments. SYSDATE.Suggested Solution: CREATE OR REPLACE PROCEDURE create_assignment (p_assign_descrip IN assessments. Oracle Academy 12 Database Programming with PL/SQL Copyright © 2010.NEXTVAL. Suggested Solution: CREATE OR REPLACE PROCEDURE enter_student_grade (p_cl_assessment_id IN class_assessments. p_assessment_id). END create_assignment.p_class_id. p_numeric_grade. COMMIT.1. END enter_student_grade. COMMIT. Find the file called enter_student_grade. STU_ID and ASSESSMENT_ID as IN parameters. SYSDATE. Oracle. class_id. . Many IN arguments. Use “today‟s” date for the DATE_TURNED_IN.101. p_assign_descrip). stu_id. p_stu_id IN class_assessments.stu_id%TYPE. All rights reserved.assessment_id%TYPE) IS BEGIN INSERT INTO class_assessments (class_assessment_id. p_numeric_grade IN class_assessments. Accept a NUMERIC_GRADE.class_id%TYPE.class_assessment_id%TYPE. CLASS_ASSESSMENT_ID. p_assessment_id IN class_assessments. Tables used: CLASS_ASSESSMENTS Topics Incorporated ==> SQL INSERT.description%TYPE) IS BEGIN INSERT INTO assessments (assessment_id.numeric_grade%TYPE.sql and rewrite it as a procedure that a teacher can run to insert the student's grade on a particular assignment. numeric_grade. assessment_id) VALUES (p_cl_assessment_id. description) VALUES (assessment_id_seq. CLASS_ID. 10. END. p_stu_id. To test: BEGIN Enter_student_grade(102.

STU_ID. v_end_date DATE. Display only enrollments between those two dates. Default values with IN parameters. and include a note about the date range. and STATUS. Suggested Solution: CREATE OR REPLACE PROCEDURE show_missing_grades (p_start_date IN DATE DEFAULT NULL.11. '01-AUG-05'). ELSE v_start_date := p_start_date.'). Write your procedure so the start_date and end_date are optional. DBMS_OUTPUT. If both dates are not entered. The listing will show all enrollments for the past year. DBMS_OUTPUT. END IF. Rewrite the program stored in the file show_missing_grades. For each enrollment.sql to be a procedure. list the CLASS_ID. v_end_date := SYSDATE. Tables used: ENROLLMENTS Topics Incorporated ==> SQL with BETWEEN. display all applicable enrollments for the past year. MONTHS_BETWEEN or other way to find the “past year. status FROM enrollments WHERE final_numeric_grade IS NULL AND final_letter_grade IS NULL AND enrollment_date BETWEEN p_start_date AND p_end_date ORDER BY enrollment_date DESC. END. . v_end_date := P_end_date. Dates.PUT_LINE Oracle Academy 13 Database Programming with PL/SQL Copyright © 2010. stu_id. Order the output by ENROLLMENT_DATE with the most recent enrollments first.PUT_LINE ('You have not specified both dates.” To test: BEGIN show_missing_grades('01-AUG-01'. v_start_date DATE. Oracle.-12). BEGIN IF p_start_date IS NULL OR p_end_date IS NULL THEN v_start_date := ADD_MONTHS(SYSDATE. All rights reserved. p_end_date IN DATE DEFAULT NULL) IS CURSOR no_grades_cur IS SELECT class_id. NULL values in a database column. Accept a start_date and end_date to establish a date range.

').PUT_LINE ('The following enrollments have no grade.class_id || ' – Student ID ' || no_grades_rec. Accept a CLASS_ID. DBMS_OUTPUT.('Date range: Between ' || v_start_date || ' and ' || v_end_date || '. .sql and rewrite it as a function. END. Suggested Solution: CREATE OR REPLACE FUNCTION compute_average_grade (p_class_id IN enrollments.'). BEGIN v_grade := compute_average_grade(6).final_numeric_grade%TYPE.stu_id || ' with a status of: ' ||no_grades_rec. Tables used: ENROLLMENTS Topics Incorporated ==> SQL with AVG function To test: (there will be no output since there are no final grades in the table) DECLARE v_grade NUMBER. Find the file called compute_average_grade. FOR no_grades_rec IN no_grades_cur LOOP DBMS_OUTPUT. BEGIN SELECT AVG(final_numeric_grade) INTO v_avg_grade FROM enrollments WHERE class_id = p_class_id. All rights reserved. Oracle.status). END compute_average_grade. DBMS_OUTPUT.PUT_LINE ('Class ID ' || no_grades_rec. END show_missing_grades. RETURN v_avg_grade. 12. Return the average grade.class_id%TYPE) RETURN NUMBER IS v_avg_grade enrollments. Oracle Academy 14 Database Programming with PL/SQL Copyright © 2010.PUT_LINE(v_grade). END LOOP.

'01-AUG-06').course_id%TYPE) RETURN NUMBER IS num_classes PLS_INTEGER.sql to a procedure. INSTRUCTORS.ENROLLMENTS Topics Incorporated ==> Calling a function from a procedure. . Find the file called count_classes_per_course. To test: BEGIN show_class_offerings('01-AUG-01'. Oracle. END. Return the number of classes offered for that course. Find the average grade by a call to the function compute_average_grade. instructor FIRST_NAME and LAST_NAME. Oracle Academy 15 Database Programming with PL/SQL Copyright © 2010. SQL Join. For each class found. Accept a start date and end date.PUT_LINE(v_classes). BEGIN v_classes := count_classes_per_course(1001). Tables used: CLASSES Topics Incorporated ==> SQL SELECT with COUNT. and average grade. END count_classes_per_course. Accept a COURSE_ID. %TYPE. BEGIN SELECT COUNT(*) INTO v_num_classes FROM classes WHERE course_id = p_course_id. display the CLASS_ID. RETURN v_num_classes. using dates. Tables used: CLASSES. DBMS_OUTPUT. 14. END. All rights reserved. COURSES. Convert the file show_class_offerings. To test: DECLARE v_classes PLS_INTEGER.13.sql and rewrite it as a function. course TITLE and SECTION_CODE. START_DATE. Suggested Solution: CREATE OR REPLACE FUNCTION count_classes_per_course (p_course_id IN classes.

FOR classes_info_rec IN classes_info_cur LOOP -. p_end_date IN DATE) IS v_avg_grade NUMBER. Make the following public: show_missing_grades.call the compute_average_grade function v_avg_grade := compute_average_grade (classes_info_rec.instr_id = i.2. COURSES Topics Incorporated: Creating a package.section_code ).PUT_LINE ( 'Class ID ' || classes_info_rec.last_name || ' – Course Title '|| classes_info_rec. cour. BEGIN DBMS_OUTPUT. i.course_id = cour. CURSOR classes_info_cur IS SELECT cl.last_name. cl.class_id).').'). show_class_offerings.title.start_date || ' – Instructor ' || classes_info_rec. DBMS_OUTPUT. Public vs.Start Date ' || classes_info_rec.PUT_LINE ('Date range: Between ' || p_start_date || ' and ' || p_end_date || '.PUT_LINE ('Classes Information.first_name || ' ' || classes_info_rec. . END show_class_offerings.section_code FROM classes cl. 15. All rights reserved. Oracle.start_date. i.4.instructor_id ORDER BY 1.class_id.first_name. Tables used: CLASSES. count_classes_per_course. Make the following private: compute_average_grade.title || ' – Offering Section ' || classes_info_rec. courses cour. END LOOP.course_id AND cl. cour. Private package constructs.Suggested Solution: CREATE OR REPLACE PROCEDURE show_class_offerings (p_start_date IN DATE. instructors i WHERE start_date BETWEEN p_start_date AND p_end_date AND cl. Oracle Academy 16 Database Programming with PL/SQL Copyright © 2010.class_id || ' – Average Grade '|| v_avg_grade || ' . INSTRUCTORS. Create a package called admin_tools_package incorporating procedure and functions you wrote in steps K to N. DBMS_OUTPUT.

--PACKAGE SPEC CREATE OR REPLACE PACKAGE admin_tools_package IS -.This procedure will list classes offered PROCEDURE show_class_offerings (p_start_date IN DATE. -. FUNCTION count_classes_per_course (p_course_id IN classes. RETURN v_avg_grade.This procedure will show missing grades for a class.class_id%TYPE) RETURN NUMBER IS v_avg_grade enrollments.course_id%TYPE) RETURN NUMBER. --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. END admin_tools_package. . PROCEDURE show_missing_grades (p_start_date IN DATE DEFAULT ADD_MONTHS(SYSDATE.-12). All rights reserved. --This procedure will show missing grades for a class.final_numeric_grade%TYPE. BEGIN SELECT AVG(final_numeric_grade) INTO v_avg_grade FROM enrollments WHERE class_id = p_class_id. p_end_date IN DATE).This function will count the number of classes per course. Oracle Academy 17 Database Programming with PL/SQL Copyright © 2010. FUNCTION compute_average_grade (p_class_id IN enrollments. Oracle.-12). -. p_end_date IN DATE DEFAULT SYSDATE). -------------------------------------------------------PROCEDURE show_missing_grades (p_start_date IN DATE DEFAULT ADD_MONTHS(SYSDATE. END compute_average_grade.

p_end_date IN DATE DEFAULT SYSDATE) IS CURSOR no_grades_cur IS SELECT class_id. DBMS_OUTPUT. DBMS_OUTPUT.').course_id AND cl.'). --This procedure will list classes offered -------------------------------PROCEDURE show_class_offerings (p_start_date IN DATE. .instructor_id ORDER BY 1. status FROM enrollments WHERE final_numeric_grade IS NULL AND final_letter_grade IS NULL AND enrollment_date BETWEEN p_start_date AND p_end_date ORDER BY enrollment_date DESC.PUT_LINE ('Class ID ' || no_grades_rec. Oracle.class_id. p_end_date IN DATE) IS v_avg_grade NUMBER. cl.2.').stu_id || ' with a status of: ' ||no_grades_rec. stu_id. The listing will show all enrollments for the past year.4. -BEGIN Oracle Academy 18 Database Programming with PL/SQL Copyright © 2010. cour. CURSOR classes_info_cur IS SELECT cl.status).PUT_LINE ('You have not specified both dates.section_code FROM classes cl. instructors i WHERE start_date BETWEEN p_start_date and p_end_date AND cl. All rights reserved. cour.PUT_LINE ('Date range: Between ' || p_start_date || ' and ' || p_end_date || '.start_date.title. BEGIN IF p_start_date IS NULL OR p_end_date IS NULL THEN DBMS_OUTPUT. END IF.first_name.last_name. i. END show_missing_grades. FOR no_grades_rec IN no_grades_cur LOOP DBMS_OUTPUT.class_id || ' – Student ID ' || no_grades_rec. END LOOP.course_id = cour.instr_id = i.PUT_LINE ('The following enrollments have no grade. courses cour. i.

last_name || ' – Course Title '|| classes_info_rec. RETURN v_num_classes.section_code ). END count_classes_per_course.class_id || ' – Average Grade '|| v_avg_grade || ' .PUT_LINE ( 'Class ID ' || classes_info_rec. All rights reserved.course_id%TYPE) RETURN NUMBER IS v_num_classes PLS_INTEGER.'). END admin_tools_package.start_date || ' – Instructor ' || classes_info_rec.'). FOR classes_info_rec IN classes_info_cur LOOP v_avg_grade := compute_average_grade (classes_info_rec. . Oracle. DBMS_OUTPUT.class_id). -----------------------------------------------------FUNCTION count_classes_per_course (p_course_id IN classes.PUT_LINE ('Date range: Between ' || p_start_date || ' and ' || p_end_date || '. DBMS_OUTPUT. END show_class_offerings.title || ' – Offering Section ' || classes_info_rec.DBMS_OUTPUT.first_name || ' ' || classes_info_rec. BEGIN SELECT COUNT(*) INTO v_num_classes FROM classes WHERE course_id = p_course_id.PUT_LINE ('Classes Information. Oracle Academy 19 Database Programming with PL/SQL Copyright © 2010.Start Date ' || classes_info_rec. --This function will count the number of classes per course. END LOOP.

stu_id%TYPE. p_class_id IN enrollments. Utilize the overloading feature of the PLSQL package.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. to add the following functionality: 1. Your output should look something like this: Enrollment Report Student Id Enrollment Date Class id 101 12-AUG-04 1 102 12-AUG-04 1 103 12-AUG-04 1 104 12-AUG-04 1 *** END OF REPORT ***  Hints: The Exceptions used with UTL_FILE. within the most recent 6 years.  When the procedure is called without a parameter. Procedure enroll_student_in_class (p_stu_id IN enrollments.txt’ and is stored in the operating system directory referenced by the Oracle directory object ‘'WF_FLAGS'.stu_id%TYPE) The Assignment and Deliverables: Modify the student_class_list procedure in the package.Part 2: Managing Students and Grades (enrollments_package) The enrollments_package you created in Part 1 contains the following public procedures: 1.class_id%TYPE) 2. All rights reserved. The external file is named „student_class_list. p_class_id IN enrollments.stu_id%TYPE. Use DBMS_OUTPUT to display the content of the external file. to overload the student_class_list procedure as follows:  When the STU_ID parameter is passed. the procedure should display a list of classes for all students in which they have been enrolled. the procedure should display a list of classes in which the student has been enrolled. Oracle. Create a procedure read_external_file. .class_id%TYPE) 3.  Oracle Academy 20 Database Programming with PL/SQL Copyright © 2010. 2. Procedure student_class_list (p_stu_id IN enrollments. within the most recent 6 years. to read an external text file stored outside the database as an operating system text file. Procedure drop_student_from_class(p_stu_id IN enrollments.

END.  Students must use a Directory object WF_FLAGS that is part of the standard course setup. Oracle Academy 21 Database Programming with PL/SQL Copyright © 2010. p_class_id IN enrollments.txt’ is provided for you. p_class_id IN enrollments. END enrollments_package.read_external_file.Overloaded procedure will list Enrollment date and class ids for a student PROCEDURE student_class_list (p_stu_id IN enrollments. .stu_id%TYPE. -.class_id%TYPE ) . Oracle.This procedure will drop a student from a class PROCEDURE drop_student_from_class (p_stu_id IN enrollments. To test: BEGIN enrollments_package.Incorporated Topics for problems 1 and 2:  Overloading procedures in a package. This is why the text file „student_class_list.  Oracle Corporation security rules do allow Academy participants to read but not create external text files (using UTL_FILE) on database server machines. -. Oracle Directory names are case sensitive.Overloaded procedure will list Enrollment date and class ids for all students PROCEDURE student_class_list. PROCEDURE read_external_file. Part 2: Suggested Solution --PACKAGE SPEC CREATE OR REPLACE PACKAGE enrollments_package IS -.This procedure will enroll a student in a class. -. so the students must type it in exactly as above. All rights reserved.stu_id%TYPE).stu_id%TYPE.  Reading external files with the UTL_FILE package. PROCEDURE enroll_student_in_class (p_stu_id IN enrollments.class_id%TYPE).

IF SQL%ROWCOUNT = 0 THEN RAISE e_not_enrolled. e_already_enrolled EXCEPTION. END enroll_student_in_class. IF v_times_enrolled <> 0 THEN RAISE e_already_enrolled. p_class_id IN enrollments. 'Enrolled'). Oracle.class_id%TYPE) IS e_not_enrolled EXCEPTION. COMMIT. BEGIN SELECT COUNT(*) INTO v_times_enrolled FROM enrollments WHERE class_id = p_class_id AND stu_id = p_stu_id.PUT_LINE('Student ' || p_stu_id || ' is already enrolled in class '|| p_class_id). status) VALUES( SYSDATE.class_id%TYPE) IS v_times_enrolled PLS_INTEGER. stu_id. END IF. class_id. EXCEPTION WHEN e_already_enrolled THEN DBMS_OUTPUT. PROCEDURE enroll_student_in_class (p_stu_id IN enrollments. EXCEPTION Oracle Academy 22 Database Programming with PL/SQL Copyright © 2010.--PACKAGE BODY CREATE OR REPLACE PACKAGE BODY enrollments_package IS -. p_stu_id.stu_id%TYPE.stu_id%TYPE.This procedure will enroll a student in a class. -.This procedure will drop a student from a class PROCEDURE drop_student_from_class (p_stu_id IN enrollments. BEGIN DELETE FROM enrollments WHERE class_id = p_class_id AND stu_id = p_stu_id. p_class_id. . END IF. p_class_id IN enrollments. All rights reserved. INSERT INTO enrollments (enrollment_date. COMMIT.

Oracle Academy 23 Database Programming with PL/SQL Copyright © 2010.WHEN e_not_enrolled THEN DBMS_OUTPUT.This procedure will list a student‟s enrollments -. -. status. END student_class_list. FOR stu_class_rec IN stu_class_cur LOOP DBMS_OUTPUT.PUT_LINE('Class: ' ||stu_class_rec.class_id.class_id || ' Enrolled on: ' || stu_class_rec. END drop_student_from_class.PUT_LINE('Student ' || p_stu_id ||' is not enrolled in class '|| p_class_id).Overloaded procedure with no parameter PROCEDURE student_class_list IS CURSOR stu_class_cur IS SELECT enrollment_date. Oracle. BEGIN DBMS_OUTPUT. END LOOP. FOR stu_class_rec IN stu_class_cur LOOP DBMS_OUTPUT.status ). -.PUT_LINE('Student ' || p_stu_id || ' is enrolled in the following classes:').PUT_LINE('Student: ' || stu_class_rec.This procedure will list all students -.-72) and SYSDATE ORDER BY stu_id. enrollment_date . BEGIN DBMS_OUTPUT. . class_id.status ).stu_id || ' Class: ' ||stu_class_rec.stu_id%TYPE) IS CURSOR stu_class_cur IS SELECT enrollment_date. stu_id FROM enrollments WHERE enrollment_date BETWEEN ADD_MONTHS (SYSDATE.enrollment_date || ' and has a status of: '|| stu_class_rec. status FROM enrollments WHERE stu_id = p_stu_id AND enrollment_date BETWEEN ADD_MONTHS (SYSDATE. END LOOP.class_id || ' Enrolled on: ' || stu_class_rec.-72) and SYSDATE. class_id. All rights reserved.Overloaded procedure with one parameter PROCEDURE student_class_list (p_stu_id IN enrollments.PUT_LINE('Students are enrolled in the following classes:').enrollment_date || ' and has a status of: '|| stu_class_rec.

END. -PROCEDURE read_external_file IS file UTL_FILE.PUT_LINE( v_line ). 'END OF FILE. v_line). file := UTL_FILE. the NO_DATA_FOUND exception is raised WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR(-20005. --Procedure read_external_file to read and display an external operating system text file. DBMS_OUTPUT. WHEN UTL_FILE.GET_LINE(file . 'student_class_list. EXCEPTION WHEN NO_DATA_FOUND THEN NULL.Nested Block to handle end of file errors locally. 'Unable to read the file. 'r'). END read_external_file.INVALID_FILEHANDLE THEN RAISE_APPLICATION_ERROR(-20006.'Invalid File.txt'. Oracle. BEGIN LOOP UTL_FILE. Oracle Academy 24 Database Programming with PL/SQL Copyright © 2010.FILE_TYPE. -.FOPEN ('WF_FLAGS'. v_line varchar2(1024).').END student_class_list.').INVALID_OPERATION THEN RAISE_APPLICATION_ERROR (-20007. END LOOP. EXCEPTION --If no text was read due to end of file. All rights reserved. WHEN UTL_FILE. END enrollments_package.'). BEGIN --the number of bytes returned will be 1024 or less if a line terminator is seen. . 'Unable to read or operate as requested.READ_ERROR THEN RAISE_APPLICATION_ERROR (-20008.'). WHEN UTL_FILE.

-. Procedure show_missing_grades (p_start_date IN DATE DEFAULT NULL.This procedure will show missing grades for a class.class_id%TYPE) RETURN NUMBER This function is private in this package. p_end_date IN DATE) 3. . FUNCTION count_classes_per_course (p_course_id IN classes. Part 3: Suggested Solution --PACKAGE SPEC CREATE OR REPLACE PACKAGE admin_tools_package IS -. All rights reserved. To test: BEGIN admin_tools_package.Part 3: School Administrator’s Tools (admin_tools_package) The admin_tools_package you created in Part I contains the following programs: 1. Procedure show_class_offerings (p_start_date IN DATE. Recompile and test the package. Utilize the forward declaration concept to be able to move the body of the private function compute_average_grade to anywhere in the package body. p_end_date IN DATE DEFAULT NULL) 2.show_class_offerings('01-AUG-01'. p_end_date IN DATE DEFAULT NULL). Function count_classes_per_course (p_course_id IN classes. -.'01-AUG-06'). Oracle. END.This procedure will list classes offered PROCEDURE show_class_offerings (p_start_date IN DATE. Oracle Academy 25 Database Programming with PL/SQL Copyright © 2010. PROCEDURE show_missing_grades(p_start_date IN DATE DEFAULT NULL. Function compute_average_grade (p_class_id IN enrollments.course_id%TYPE) RETURN NUMBER 4.course_id%TYPE) RETURN NUMBER.This function will count the number of classes per course. p_end_date IN DATE). The Assignment and Deliverables: 1.

-12). --This procedure will show missing grades for a class. The listing will show all enrollments for the past year. All rights reserved.').'). v_start_date DATE. . ---------------------------------------------------PROCEDURE show_missing_grades (p_start_date IN DATE DEFAULT NULL. Oracle.PUT_LINE ('Date range: Between ' || v_start_date || ' and ' || v_end_date || '. p_end_date IN DATE DEFAULT NULL) IS CURSOR no_grades_cur IS SELECT class_id. v_end_date DATE. DBMS_OUTPUT. --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. BEGIN IF p_start_date IS NULL OR p_end_date IS NULL THEN v_start_date := ADD_MONTHS(SYSDATE. stu_id.END admin_tools_package. v_end_date := P_end_date. v_end_date := SYSDATE.class_id%TYPE) RETURN NUMBER. ELSE v_start_date := p_start_date.PUT_LINE ('You have not specified both dates. DBMS_OUTPUT. status FROM enrollments WHERE final_numeric_grade IS NULL AND final_letter_grade IS NULL AND enrollment_date BETWEEN p_start_date AND p_end_date ORDER BY enrollment_date DESC. END IF. --Forward Declaration FUNCTION compute_average_grade (p_class_id IN enrollments. DBMS_OUTPUT.PUT_LINE Oracle Academy 26 Database Programming with PL/SQL Copyright © 2010.

CURSOR classes_info_cur IS SELECT cl.').PUT_LINE ( 'Class ID ' || classes_info_rec.2.instr_id = i.start_date. END LOOP. DBMS_OUTPUT.title. cour.class_id || ' – Average Grade '|| v_avg_grade || ' .course_id = cour.course_id AND cl. FOR classes_info_rec IN classes_info_cur LOOP v_avg_grade := compute_average_grade (classes_info_rec.first_name || ' ' || classes_info_rec.class_id.').').4.section_code FROM classes cl.title || ' – Offering Section ' || classes_info_rec. i. FOR no_grades_rec IN no_grades_cur LOOP DBMS_OUTPUT.status).PUT_LINE ('Date range: Between ' || p_start_date || ' AND ' || p_end_date || '. cl. instructors i WHERE start_date BETWEEN p_start_date AND p_end_date AND cl.stu_id || ' with a status of: ' ||no_grades_rec.last_name.class_id || ' – Student ID ' || no_grades_rec.Start Date ' || classes_info_rec.instructor_id ORDER BY 1. --This procedure will list classes offered ---------------------------------PROCEDURE show_class_offerings (p_start_date IN DATE.start_date || ' – Intructor ' || classes_info_rec. DBMS_OUTPUT.('The following enrollments have no grade. END show_class_offerings. courses cour. END LOOP. Oracle Academy 27 Database Programming with PL/SQL Copyright © 2010. cour.PUT_LINE ('Classes Information. p_end_date IN DATE) IS v_avg_grade NUMBER. END show_missing_grades.PUT_LINE ('Class ID ' || no_grades_rec.last_name || ' – Course Title '|| classes_info_rec. All rights reserved. i. Oracle.first_name. . -BEGIN DBMS_OUTPUT.section_code ).class_id).

stu_id NUMBER(7. RETURN v_avg_grade. .class_id%TYPE) RETURN NUMBER IS v_avg_grade enrollments. Oracle. Create a row level trigger audit_grade_change to keep a history of all the changes made to students‟ final letter grade. FUNCTION count_classes_per_course (p_course_id IN classes. BEGIN SELECT AVG(final_numeric_grade) INTO v_avg_grade FROM enrollments WHERE class_id = p_class_id. END count_classes_per_course. Oracle Academy 28 Database Programming with PL/SQL Copyright © 2010. All rights reserved. Part 4: Create Database Triggers 1. new_final_grade CHAR(1)). END admin_tools_package. BEGIN SELECT COUNT(*) INTO v_num_classes FROM classes WHERE course_id = p_course_id.0). END compute_average_grade. old_final_grade CHAR(1). enroll_date DATE. Create the grade_change_history table as follows: CREATE TABLE grade_change_history (time_stamp DATE. class_id NUMBER(6.0). RETURN v_num_classes. 2.--This function will count the number of classes per course. The grade change is recorded every time the FINAL_LETTER_GRADE field is updated in the ENROLLMENTS table.course_id%TYPE) RETURN NUMBER IS v_num_classes PLS_INTEGER.final_numeric_grade%TYPE. FUNCTION compute_average_grade (p_class_id IN enrollments.

END. it should insert a record in the GRADE_CHANGE_HISTORY table. All rights reserved. :OLD. old_final_grade. in the ENROLLMENTS table. Part 4: Suggested Solution --Trigger Code -----------------CREATE OR REPLACE TRIGGER audit_grade_change AFTER UPDATE OF final_letter_grade ON enrollments FOR EACH ROW BEGIN INSERT INTO grade_change_history(time_stamp.enrollment_date.stu_id. Oracle.  Topics Incorporated: Row level DML trigger Tables Used: ENROLLMENTS. 2.stu_id. . Test your trigger by updating the final_letter_grade for a student. GRADE_CHANGE_HISTORY To test: 1. :NEW. UPDATE enrollments SET final_letter_grade = 'A' WHERE stu_id = 101. class_id. Every time the trigger is fired. enroll_date. :OLD.class_id. Oracle Academy 29 Database Programming with PL/SQL Copyright © 2010. recording the old grade and the new grade for each student.final_letter_grade. :OLD.final_letter_grade). new_final_grade) VALUES(SYSDATE. :OLD. SELECT * FROM grade_change_history.

All rights reserved. Use the following guidelines:  When the function is called with two parameters: manage_triggers (p_tablename. 'ENABLE'). COURSES To test: -Pass a table name to P_TABLENAME parameter -Pass „disable‟ or „enable‟ string to P_ACTION parameter. or to compile a trigger. BEGIN manage_triggers_package. Hints:  Use the ALTER TABLE command to disable/enable all triggers of a table programmatically.  When the function is called with only one parameter manage_triggers (p_trigger_name)  Pass a trigger name to P_TRIGGER_NAME parameter.  Code an exception handling block to display a message if the DDL command fails.manage_triggers('audit_grade_change'). p_action)  Pass a table name to P_TABLENAME parameter.  Use Native Dynamic SQL to execute the DDL commands programmatically. Oracle Academy 30 Database Programming with PL/SQL Copyright © 2010. Create a package manage_triggers_package that contains two overloaded functions called manage_triggers. INSTRUCTORS. Native Dynamic SQL. -Pass a trigger name to P_TRIGGER_NAME parameter.manage_triggers('ENROLLMENTS'. Topics Incorporated: Forward Declaration. BEGIN manage_triggers_package.  Use the ALTER TRIGGER command to compile the trigger programmatically. END.Part 5: Create manage_triggers_package The Assignment and Deliverables: 1. END. exception handling. Oracle.  Pass „disable‟ or „enable‟ string to P_ACTION parameter. Overloading. The functions are invoked to disable/enable all triggers for a table. Tables used: CLASSES. .

Part 5: Suggested Solution --Create a new package to manage the database triggers. END. --PACKAGE BODY CREATE OR REPLACE PACKAGE BODY manage_triggers_package IS --Overloaded Procedure manage triggers -----------------------------PROCEDURE manage_triggers(p_tablename IN VARCHAR2. Oracle. DBMS_OUTPUT. ').').PUT_LINE(p_trigger_name|| ' Trigger Compiled. All rights reserved. EXCEPTION WHEN OTHERS THEN Oracle Academy 31 Database Programming with PL/SQL Copyright © 2010. p_mode IN VARCHAR2). DBMS_OUTPUT. --Overloaded Procedure manage triggers -----------------------------PROCEDURE manage_triggers(p_trigger_name IN VARCHAR2) IS BEGIN EXECUTE IMMEDIATE 'ALTER TRIGGER '||p_trigger_name|| ' COMPILE'. . p_mode IN VARCHAR2) IS BEGIN EXECUTE IMMEDIATE 'ALTER TABLE '||p_tablename||' '|| p_mode || ' All TRIGGERS'. PROCEDURE manage_triggers(p_trigger_name IN VARCHAR2). END manage_triggers_package.PUT_LINE(p_tablename || ' Altered. EXCEPTION WHEN OTHERS THEN RAISE_APPLICATION_ERROR(-20001. --PACKAGE SPEC CREATE OR REPLACE PACKAGE manage_triggers_package IS PROCEDURE manage_triggers(p_tablename IN VARCHAR2.'DDL Command Failed.').

RAISE_APPLICATION_ERROR(-20001. END.'DDL Command Failed. Oracle Academy 32 Database Programming with PL/SQL Copyright © 2010.'). END manage_triggers_package. Oracle. . All rights reserved.