tags:

views:

117

answers:

7

So I have these tables:

STUDENTS: Student ID - First name - Last name - Email

COURSES: Catalog ID - Course Name - Description

TERMS: Term ID - Start Date - End Date

COURSEINSTANCES: CourseInstance ID - Catalog ID - Term ID

STUDENTCOURSES: StudentCourse ID - CourseInstance ID - Student ID - Date added to database

This makes it easy to see which students have taken which courses. I'm not sure how to go about finding out which students have NOT taken a particular course.

Doing something like this:

WHERE ((CourseInstances.CatalogLookup)<>504)

will just give me a list of courses taken by students that do not equal catalog number 504 like this:

Tara - 501

Tara - 502

Tara - 505

John - 503

So for example I've taken 504. Therefore I do not want me to show up on this list. The SQL above will just show all of my courses that are not 504, but it will not exclude me from the list.

Any ideas? Is this possible?

+1  A: 

You should read about outer joins.

Andrew Bezzub
A: 

homework? use set operators.

select all students MINUS select any student who has taken this course...

Randy
It's not homework. It's work-work. Your answer is kind of like just restating my question, I'm not sure how to use it to solve it.
Tara
No. MS Access does not have the MINUS operator.
FrustratedWithFormsDesigner
+5  A: 

I prefer this syntax over outer joins, IMO it's easier to read:

select * 
from STUDENTS 
where StudentID not in 
(
    select StudentID 
    from STUDENTCOURSES s 
    inner join COURSEINSTANCES c on s.CourseInstanceID  = c.CourseInstanceID 
    where c.CatalogID = 504
)

In the nested query, you select the StudentIDs of all students who HAVE taken course 504.

Then, you select all the students whose StudentIDs are not included in the nested query.

EDIT:
As ChrisJ already said, the c and the s are aliases for the table names.
Without them, the query would look like this:

select * 
from STUDENTS 
where StudentID not in 
(
    select StudentID 
    from STUDENTCOURSES 
    inner join COURSEINSTANCES c on STUDENTCOURSES.CourseInstanceID = COURSEINSTANCES .CourseInstanceID 
    where CatalogID = 504
)

I always use aliases because:
a) I'm too lazy to type the table names more often than necessary
b) IMO it's easier to read, especially when you join tables with long names

haarrrgh
Hmm. I understand the concept but not the execution. Can you explain what the c and s signify?
Tara
They are table aliases. They are just little names you give the table so you don't have to type out the whole name again later. They should really read STUDENTCOURSES AS s though.
Chris J
I got it! Thanks for your help!
Tara
Not that Jet/ACE sometimes fails to use the indexes on both sides of a NOT IN (SELECT ...) criterion. It uniformly uses the indexes with plain IN, but for some reason, sometimes it can't use both of the with NOT IN (and I've never found a predictable pattern to when it happens). Because of that, I'd tend to use an OUTER JOIN instead of an IN () clause. However, if the result needs to be editable, you'll probably want to use the IN version instead.
David-W-Fenton
+1  A: 

Try something like this:

SELECT * 
FROM Users 
WHERE UserID NOT IN
( SELECT UserID
  FROM 
    Users
  INNER JOIN
    ClassesTaken ON Users.UserID = ClassesTaken.UserID AND ClassesTaken.ClassNumber = 504)
Chris J
+1  A: 

Three main ways in Access

  • NOT IN (Be careful to exclude any NULLs if there is any possibility of them appearing in the sub query)
  • OUTER JOIN and filter on NULL (may need DISTINCT added)
  • NOT EXISTS

Other RDBMSs also have EXCEPT or MINUS

Martin Smith
OP specified MS Access, so `except` / `minus` are not options.
FrustratedWithFormsDesigner
@Frustrated - Yep just noticed that myself :-)
Martin Smith
+1 "NOT IN with NULLs"
HansUp
FWIW MS Access also has `ANY` and its synonym `SOME` (and `ALL` but doesn't apply to this question).
onedaywhen
A: 
SELECT * FROM students 
WHERE studentId not in 
(SELECT distinct studentID FROM studentCourses WHERE courseInstanceID = 504)
Denaem
A: 
select s.*
from Students s
where not exists(select 1 from 
                 StudentCourses sc 
                 join CourseInstances ci on sc.[CourseInstance ID] = ci.[CourseInstance ID]
                 where sc.[Student ID] = s.[Student ID] and ci.[Catalog ID] = 504)
Mike