Question

I have a university practical next week on databases. I need to create 15 queries around a scheme on a university, which looks as follows:

  • Student(Student_No, First_Name , Last_Name, Sex, Date-Of-Birth, Address, Level, Degree_Code)
  • Degree(Degree_Code, Degree_Name, School_Name)
  • Module(Module_Code, Module_Title, School_Name)
  • School(School_Name, Faculty, Head-of-School)
  • Take_Exam(Student_No, Module_Code, Mark)

I have completed 14 of the queries but I am stuck on this one:

  • Retrieve the names of students who take every Module. (Hint. use not exists).

I have been reading up on not exists queries, but I just don't even know where to start! I created this piece of code:

select students.student_no, fname, lname, count(module_code)
from students left join take_exam using (student_no)
group by student_no
having count(module_code) < 19
order by lname;

This returns all students who DON'T take all 19 modules. However, I hate the code as it involves having < 19, which meant if the amount of modules ever changed later, this value would need changes which is inefficient.

Can anyone point me in the right direction and give me some guidance on using 'not exists' queries?

Thanks, Andrew

Was it helpful?

Solution

Using not exists :

select *
from Student s1 
where not exists 
         (select 1 
          from Module 
          where Module_Code not in
                      (select Module_Code 
                       from Take_Exam 
                       where Student_No = s1.Student_No)

Explanation :

For each student s in the table Student, we'll add s to the result, iff : not exists any module in table Module such that this module is not mapped to student s in table Take_Exam.

It's not intuitive, but it's exactly the same as : "all the students who take every module"

OTHER TIPS

Without completely answering your homework for you, here's a hint that might help:

Try looking at it from another angle. Students that answered all module question will not have any null fields with a left join to the module table, correct?

Also,you probably don't need a left outer join to the table_exam... since you want only students having taken the exam.

I think, you can get distinct count of modules from module table and then use that in comparison e.g. below:

     select students.student_no, fname, lname, count(t.module_code)
     from module m, students join take_exam t using (student_no)
     group by student_no
     having count(t.module_code) = count(distinct(m.module_code)) 
     order by lname;

Please note: I changed the condition to = and join to inner join as you wanted students taking all modules.

EDIT: Using notExit:

     select students.student_no, fname, lname 
     from students 
     WHERE  NOT EXISTS (select *
                from module m, students join take_exam t using (student_no)
                group by student_no
                having count(t.module_code) < count(distinct(m.module_code)) 
                group by student_no
             )
     order by lname;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top