Reputation: 13
I am trying to create a trigger which inserts into the ALARMS table the values student_id
and course_id
when a student registers on a course without its prerequisite, but I failed.
This is my trigger:
CREATE OR REPLACE TRIGGER ALARM_TRIGGER
BEFORE INSERT OR UPDATE OF student_id, course_id ON students_courses
FOR EACH ROW
BEGIN
insert into alarms(student_id, course_id) values(:NEW.student_id, :NEW.course_id);
END;
The Tables:
1-COURSES: which have course_id (PK) and course_name.
2-STUDENTS: which have student_id (PK) and student_name.
3-STUDENTS_COURSES: which have each student with his courses.
4-PREREQUISITE_COURSES: which have prerequisite each course.
5-ALARMS: Trigger which store student_id, course_id when any student register in course without its prerequisite.
This is example of courses prerequisite table:
COURSE_NUMBER COURSE_PREREQUISITE 1 null 2 1 3 null 4 3
Upvotes: 1
Views: 519
Reputation: 5636
If a student enrolls in a course without a prerequisite, the result of querying for prerequisites will be NULL. So, if the course has a prerequisite and the student has taken the prerequisite, you want the result to be the same. That makes subsequent logic easier. So if the course has a prerequisite the student has not taken, the result will be the course id of the prerequisite (you can use that to display a meaningful error message).
The query to return NULL if the course has no prerequisite is easy:
select P.COURSE_PREREQUISITE Result
into RequiredReq
from Prerequisites P
where P.COURSE_NUMBER = :new.course_id;
Of course, it returns the course id of the prerequisite if there is one, but we'll take care of that later. Now we want to join with the STUDENTS_COURSES table:
join STUDENTS_COURSES SC
on SC.COURSE_NUMBER = P.COURSE_PREREQUISITE
and SC.Student_ID = :new.Student_ID
However, this is not going to give us everything we need. First, if the student has not taken the prerequisite, the query will return nothing so we'll get a NO_DATA_FOUND error. Second, if the student has taken the prerequisite, it will return the course id but in this case we want it to return a NULL.
Let's see what we get if we turn the inner join to a left outer join:
select P.COURSE_PREREQUISITE Result
into RequiredReq
from Prerequisites P
left join STUDENTS_COURSES SC
on SC.COURSE_NUMBER = P.COURSE_PREREQUISITE
and SC.Student_ID = :new.Student_ID
where P.COURSE_NUMBER = :new.course_id;
This gives us everything we want, but not quite in the right way. We get NULL if the prerequisite has not been met and the prerequisite value if it has. So to change it around, we just need a little logic in the query:
select case when P.Prerequisite is null then null --> No prerequisite
when SC.StudentID is not null then null --> Prerequisite met
else P.Prerequisite end Result --> Prerequisite not met
into RequiredReq
from Prerequisites P
left join STUDENTS_COURSES SC
on SC.COURSE_NUMBER = P.COURSE_PREREQUISITE
and SC.Student_ID = :new.Student_ID
where P.COURSE_NUMBER = :new.course_id;
Now a NULL means either the course has no prerequisite or the student has met the prerequisite. Only if the course has a prerequisite and the student has not met it is a value returned and that is the course number of the unmet prerequisite.
Note: this works only if, as implied in your example data, there is only one prerequisite per course. If there can be one or more prerequisites, you will probably want to change to numeric returns with 0 meaning no or all met prerequisites and non-zero meaning the number of unmet prerequisites.
Upvotes: 1