ADBMS ASSIGNMENT
J032
#Q1)
PROCEDURES :
1. Enroll New Student
Write a procedure that inserts a new student into the student table,
assigning them to a department and setting default GPA to 2.5.
SOLUTION:
CREATE OR REPLACE PROCEDURE enroll_new_student (
p_student_id IN NUMBER,
p_name IN VARCHAR2,
p_department_id IN NUMBER
)
IS
BEGIN
INSERT INTO student (
student_id,
name,
department_id,
gpa,
enrollment_date
)
VALUES (
p_student_id,
p_name,
p_department_id,
2.5,
SYSDATE
);
DBMS_OUTPUT.PUT_LINE('Student enrolled
successfully.');
END;
#TRY
BEGIN
enroll_new_student(105, 'Alice Smith', 2);
END;
2) Update Department Budget
A procedure to update the budget of a given department based on an increase
percentage.
SOLUTION:
CREATE OR REPLACE PROCEDURE update_department_budget (
p_department_id IN NUMBER,
p_increase_percent IN NUMBER
)
IS
BEGIN
UPDATE department
SET budget = budget + (budget * p_increase_percent / 100)
WHERE department_id = p_department_id;
DBMS_OUTPUT.PUT_LINE('Budget updated successfully.');
END;
#TRY
BEGIN
update_department_budget(2, 10); -- Increase budget of department 2 by
10%
END;
3)
Record Fine Payment
Write a procedure that updates the library table to mark a book as returned,
set the fine to 0, and log the return date.
SOLUTION:
CREATE OR REPLACE PROCEDURE record_fine_payment (
p_library_id IN NUMBER
)
IS
BEGIN
UPDATE library
SET
is_returned = 'Yes',
fine_amount = 0,
return_date = SYSDATE
WHERE library_id = p_library_id;
DBMS_OUTPUT.PUT_LINE('Book return recorded and fine cleared.');
END;
#try
BEGIN
record_fine_payment(201); -- Marks book as
returned for library_id 201
END;
#4)
Generate Department Report
Create a procedure to print or insert into a log table the number of students
and average GPA per department
Solution:
CREATE OR REPLACE PROCEDURE
generate_department_report
IS
CURSOR dept_cursor IS
SELECT d.department_id, d.department_name,
COUNT(s.student_id) AS student_count,
ROUND(AVG(s.gpa), 2) AS avg_gpa
FROM department d
LEFT JOIN student s ON d.department_id =
s.department_id
GROUP BY d.department_id, d.department_name;
v_dept_id department.department_id%TYPE;
v_dept_name department.department_name%TYPE;
v_student_count NUMBER;
v_avg_gpa NUMBER;
BEGIN
OPEN dept_cursor;
LOOP
FETCH dept_cursor INTO v_dept_id, v_dept_name,
v_student_count, v_avg_gpa;
EXIT WHEN dept_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Department: ' ||
v_dept_name ||
' | Students: ' || v_student_count ||
' | Avg GPA: ' || NVL(v_avg_gpa, 0));
END LOOP;
CLOSE dept_cursor;
END;
#try
BEGIN
generate_department_report;
END;
#5)
Clear Graduated Students
A procedure to delete students whose enrollment_date is more than 4 years
ago and have GPA above 3.0.
Solution:
CREATE OR REPLACE PROCEDURE
clear_graduated_students
IS
BEGIN
DELETE FROM student
WHERE enrollment_date < ADD_MONTHS(SYSDATE, -
48) -- 4 years = 48 months
AND gpa > 3.0;
DBMS_OUTPUT.PUT_LINE('Graduated students
cleared successfully.');
END;
#try
BEGIN
clear_graduated_students;
END;
FUNCTIONS
1)Calculate Outstanding Balance
Function that takes student_id and returns their total amount_due from the
finance table.
SOLUTION:
CREATE OR REPLACE FUNCTION
calculate_outstanding_balance (
p_student_id IN NUMBER
) RETURN NUMBER
IS
v_total_due NUMBER := 0;
BEGIN
SELECT NVL(SUM(amount_due), 0)
INTO v_total_due
FROM finance
WHERE student_id = p_student_id;
RETURN v_total_due;
END;
#TRY
DECLARE
v_balance NUMBER;
BEGIN
v_balance := calculate_outstanding_balance(101);
DBMS_OUTPUT.PUT_LINE('Outstanding Balance: ' ||
v_balance);
END;
2)
Get Department Name by Student ID
Function that returns the department name for a given student.
SOLUTION:
CREATE OR REPLACE FUNCTION get_department_name (
p_student_id IN NUMBER
) RETURN VARCHAR2
IS
v_department_name VARCHAR2(100);
BEGIN
SELECT d.department_name
INTO v_department_name
FROM student s
JOIN department d ON s.department_id = d.department_id
WHERE s.student_id = p_student_id;
RETURN v_department_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN 'No Department Found';
WHEN OTHERS THEN
RETURN 'Error';
END;
#TRY
DECLARE
v_dept_name VARCHAR2(100);
BEGIN
v_dept_name := get_department_name(101);
DBMS_OUTPUT.PUT_LINE('Department: ' ||
v_dept_name);
END;
3)
Student Full Status
Return a string summary: 'Name (GPA), Department, Outstanding Due' given a
student_id.
SOLUTION:
CREATE OR REPLACE FUNCTION get_student_full_status (
p_student_id IN NUMBER
) RETURN VARCHAR2
IS
v_name student.name%TYPE;
v_gpa student.gpa%TYPE;
v_department_name department.department_name
%TYPE;
v_due NUMBER := 0;
v_status VARCHAR2(300);
BEGIN
-- Get student name, GPA, department_id
SELECT s.name, s.gpa, d.department_name
INTO v_name, v_gpa, v_department_name
FROM student s
JOIN department d ON s.department_id = d.department_id
WHERE s.student_id = p_student_id;
-- Calculate total outstanding due
SELECT NVL(SUM(amount_due), 0)
INTO v_due
FROM finance
WHERE student_id = p_student_id;
-- Combine into status string
v_status := v_name || ' (' || v_gpa || '), ' ||
v_department_name || ', Outstanding Due: ' || v_due;
RETURN v_status;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN 'Student not found';
WHEN OTHERS THEN
RETURN 'Error occurred';
END;
/
#TRY
DECLARE
v_status VARCHAR2(300);
BEGIN
v_status := get_student_full_status(101);
DBMS_OUTPUT.PUT_LINE(v_status);
END;
/
#4)
Library Book Return Delay
Function that calculates the number of days late for a returned book.
SOLUTION:
CREATE OR REPLACE FUNCTION get_book_return_delay (
p_library_id IN NUMBER
) RETURN NUMBER
IS
v_issue_date DATE;
v_return_date DATE;
v_due_date DATE;
v_days_late NUMBER;
BEGIN
-- Get issue and return dates
SELECT issue_date, return_date
INTO v_issue_date, v_return_date
FROM library
WHERE library_id = p_library_id;
-- Calculate due date (14 days after issue)
v_due_date := v_issue_date + 14;
-- Calculate days late (if any)
v_days_late := v_return_date - v_due_date;
IF v_days_late < 0 THEN
v_days_late := 0; -- Not late
END IF;
RETURN v_days_late;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN -1; -- Book record not found
WHEN OTHERS THEN
RETURN -2; -- Error occurred
END;
/
#TRY
DECLARE
v_late_days NUMBER;
BEGIN
v_late_days := get_book_return_delay(201);
DBMS_OUTPUT.PUT_LINE('Days Late: ' || v_late_days);
END;
/
#5)
Scholarship Eligibility
Function that returns TRUE if GPA is above 3.5 and amount_due is 0.
SOLUTION:
CREATE OR REPLACE FUNCTION is_scholarship_eligible (
p_student_id IN NUMBER
) RETURN BOOLEAN
IS
v_gpa NUMBER;
v_due NUMBER;
BEGIN
-- Get GPA of the student
SELECT gpa
INTO v_gpa
FROM student
WHERE student_id = p_student_id;
-- Get total outstanding amount
SELECT NVL(SUM(amount_due), 0)
INTO v_due
FROM finance
WHERE student_id = p_student_id;
-- Check eligibility
IF v_gpa > 3.5 AND v_due = 0 THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN FALSE; -- Student not found or no finance record
WHEN OTHERS THEN
RETURN FALSE; -- On error, return false
END;
/
#TRY
DECLARE
eligible BOOLEAN;
BEGIN
eligible := is_scholarship_eligible(101);
IF eligible THEN
DBMS_OUTPUT.PUT_LINE('Eligible for Scholarship');
ELSE
DBMS_OUTPUT.PUT_LINE('Not Eligible');
END IF;
END;
/
TRIGGERS
1) Log Department Budget Changes
Trigger that logs before and after values of budget into an audit table on
update.
CREATE TABLE department_budget_audit (
audit_id NUMBER GENERATED ALWAYS AS IDENTITY,
department_id NUMBER,
old_budget NUMBER,
new_budget NUMBER,
changed_on DATE DEFAULT SYSDATE
);
CREATE OR REPLACE TRIGGER log_budget_change
BEFORE UPDATE OF budget ON department
FOR EACH ROW
BEGIN
INSERT INTO department_budget_audit (
department_id, old_budget, new_budget
) VALUES (
:OLD.department_id, :OLD.budget, :NEW.budget
);
END;
/
2)
Prevent Duplicate Emails
BEFORE INSERT trigger on student to prevent duplicate emails.
SOLUTION:
CREATE OR REPLACE TRIGGER
prevent_duplicate_emails
BEFORE INSERT ON student
FOR EACH ROW
DECLARE
v_count NUMBER;
BEGIN
SELECT COUNT(*) INTO v_count
FROM student
WHERE email = :NEW.email;
IF v_count > 0 THEN
RAISE_APPLICATION_ERROR(-20001, 'Email already
exists. Duplicate not allowed.');
END IF;
END;
/
3)
Auto Fine on Late Return
AFTER UPDATE trigger on library.return_date that calculates fine if return_date
> due_date.
SOLUTION:
CREATE OR REPLACE TRIGGER
auto_fine_on_late_return
AFTER UPDATE OF return_date ON library
FOR EACH ROW
DECLARE
v_due_date DATE;
v_days_late NUMBER;
v_fine NUMBER;
BEGIN
-- Calculate due date as issue_date + 14 days
v_due_date := :OLD.issue_date + 14;
-- Calculate days late
v_days_late := :NEW.return_date - v_due_date;
IF v_days_late > 0 THEN
v_fine := v_days_late * 2; -- $2 per day fine
UPDATE library
SET fine_amount = v_fine
WHERE library_id = :NEW.library_id;
ELSE
UPDATE library
SET fine_amount = 0
WHERE library_id = :NEW.library_id;
END IF;
END;
/
#4)
Track High Payments
AFTER INSERT trigger on finance that logs transactions over $40,000 into a
high_value_payments table.
SOLUTION:
CREATE TABLE high_value_payments (
payment_id NUMBER GENERATED ALWAYS AS
IDENTITY,
student_id NUMBER,
amount_due NUMBER,
logged_on DATE DEFAULT SYSDATE
);
CREATE OR REPLACE TRIGGER track_high_payments
AFTER INSERT ON finance
FOR EACH ROW
BEGIN
IF :NEW.amount_due > 40000 THEN
INSERT INTO high_value_payments (
student_id, amount_due
) VALUES (
:NEW.student_id, :NEW.amount_due
);
END IF;
END;
/
5)
Restrict GPA Entry
BEFORE INSERT or UPDATE on student.gpa to ensure it's between 0.0 and 4.0.
SOLUTION:
CREATE OR REPLACE TRIGGER restrict_gpa_range
BEFORE INSERT OR UPDATE OF gpa ON student
FOR EACH ROW
BEGIN
IF :NEW.gpa < 0.0 OR :NEW.gpa > 4.0 THEN
RAISE_APPLICATION_ERROR(-20002, 'GPA must be
between 0.0 and 4.0');
END IF;
END;
/
CURSORS
1) List Students per Department
Cursor that iterates through departments and prints student names
enrolled in each.
SOLUTION:
DECLARE
-- Cursor for all departments
CURSOR dept_cursor IS
SELECT department_id, department_name
FROM department;
-- Variables to hold department info
v_dept_id department.department_id%TYPE;
v_dept_name department.department_name%TYPE;
-- Cursor for students in a department
CURSOR student_cursor(p_dept_id NUMBER) IS
SELECT name
FROM student
WHERE department_id = p_dept_id;
v_student_name student.name%TYPE;
BEGIN
OPEN dept_cursor;
LOOP
FETCH dept_cursor INTO v_dept_id, v_dept_name;
EXIT WHEN dept_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Department: ' || v_dept_name);
-- Open inner cursor for students
OPEN student_cursor(v_dept_id);
LOOP
FETCH student_cursor INTO v_student_name;
EXIT WHEN student_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(' - ' || v_student_name);
END LOOP;
CLOSE student_cursor;
DBMS_OUTPUT.PUT_LINE('-----------------------------');
END LOOP;
CLOSE dept_cursor;
END;
/
2)
Outstanding Library Fines
Cursor that scans library and lists all students with unpaid fines over $100.
SOLUTION:
DECLARE
-- Cursor to find students with fines > $100
CURSOR fine_cursor IS
SELECT l.student_id, s.name, l.fine_amount
FROM library l
JOIN student s ON l.student_id = s.student_id
WHERE l.fine_amount > 100;
-- Variables to hold data
v_student_id library.student_id%TYPE;
v_name student.name%TYPE;
v_fine library.fine_amount%TYPE;
BEGIN
OPEN fine_cursor;
LOOP
FETCH fine_cursor INTO v_student_id, v_name, v_fine;
EXIT WHEN fine_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Student: ' || v_name ||
' | ID: ' || v_student_id ||
' | Fine: $' || v_fine);
END LOOP;
CLOSE fine_cursor;
END;
/
3)
Finance Summary Cursor
Loop through each student and show total amount_paid and amount_due.
SOLUTION:
DECLARE
-- Cursor to get total paid and due for each student
CURSOR finance_cursor IS
SELECT f.student_id, s.name,
NVL(SUM(f.amount_paid), 0) AS total_paid,
NVL(SUM(f.amount_due), 0) AS total_due
FROM finance f
JOIN student s ON f.student_id = s.student_id
GROUP BY f.student_id, s.name;
-- Variables to hold data
v_student_id finance.student_id%TYPE;
v_name student.name%TYPE;
v_total_paid NUMBER;
v_total_due NUMBER;
BEGIN
OPEN finance_cursor;
LOOP
FETCH finance_cursor INTO v_student_id, v_name, v_total_paid,
v_total_due;
EXIT WHEN finance_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Student: ' || v_name ||
' | ID: ' || v_student_id ||
' | Paid: $' || v_total_paid ||
' | Due: $' || v_total_due);
END LOOP;
CLOSE finance_cursor;
END;
/
4)
Overdue Books Notification
Cursor to fetch books not returned and issue notifications (simulate by
DBMS_OUTPUT).
DECLARE
-- Cursor to find overdue books
CURSOR overdue_cursor IS
SELECT l.library_id, l.student_id, s.name, l.book_title, l.issue_date
FROM library l
JOIN student s ON l.student_id = s.student_id
WHERE l.is_returned = 'No'
AND l.issue_date + 14 < SYSDATE; -- Overdue
-- Variables to hold data
v_library_id library.library_id%TYPE;
v_student_id library.student_id%TYPE;
v_name student.name%TYPE;
v_book_title library.book_title%TYPE;
v_issue_date DATE;
v_due_date DATE;
BEGIN
OPEN overdue_cursor;
LOOP
FETCH overdue_cursor INTO v_library_id, v_student_id, v_name,
v_book_title, v_issue_date;
EXIT WHEN overdue_cursor%NOTFOUND;
-- Calculate due date
v_due_date := v_issue_date + 14;
-- Simulate notification
DBMS_OUTPUT.PUT_LINE(' Overdue Notification: ' || v_name ||
' (ID: ' || v_student_id || ') has not returned "' ||
v_book_title || '". Due on ' || TO_CHAR(v_due_date, 'DD-
MON-YYYY'));
END LOOP;
CLOSE overdue_cursor;
END;
/
5)
Average GPA by Department
Use a cursor to compute and display the average GPA per department.
SOLUTION:
DECLARE
-- Cursor to iterate departments
CURSOR dept_cursor IS
SELECT department_id, department_name
FROM department;
-- Variables to hold department data
v_dept_id department.department_id%TYPE;
v_dept_name department.department_name%TYPE;
v_avg_gpa NUMBER;
BEGIN
OPEN dept_cursor;
LOOP
FETCH dept_cursor INTO v_dept_id, v_dept_name;
EXIT WHEN dept_cursor%NOTFOUND;
-- Compute average GPA for current department
SELECT ROUND(NVL(AVG(gpa), 0), 2)
INTO v_avg_gpa
FROM student
WHERE department_id = v_dept_id;
-- Output the result
DBMS_OUTPUT.PUT_LINE('Department: ' || v_dept_name ||
' | Average GPA: ' || v_avg_gpa);
END LOOP;
CLOSE dept_cursor;
END;
/