Sinaesthetic
Sinaesthetic

Reputation: 12241

SQL query: list all items in one table that do not appear in another table

I'm working on a training tracker program and I'm at a point where I can't figure out the SQL query.

I have 3 tables: employees, trainingRecords, masterList.

employees and trainingRecords are related through the empID fkey.

trainingRecords and masterList are related through the TID fkey.

Right now the training records table is blank because nothing has been entered (all employees have no training).

I want to populate a listbox with all of the items in the masterList that are unaccounted for in the trainingRecords table.

Since the trainingRecords table is blank, it should be returning lName, fName from the employees table and docName, docNumber for all entries in the master list.

I'm stumped. Any suggestions?

Upvotes: 6

Views: 22818

Answers (4)

Eric Shen
Eric Shen

Reputation: 1

Why not use Full Join? What I use is:

Select A.* from A Full Join B on A.ID = B.ID where B.ID is NULL

Upvotes: -1

JumpingJezza
JumpingJezza

Reputation: 5675

I'm assuming you want to display all employees multiple times with the training documents they have not done yet.

SELECT a.lName, a.fName, b.docNumber, b.docName 
FROM
(SELECT e.lName, e.fName, t.TID 
 FROM employees e
 LEFT JOIN trainingRecords t ON e.empID = t.empID
) AS a,
(SELECT m.docNumber, m.docName, t.TID
 FROM masterList m
 LEFT JOIN trainingRecords t ON m.TID = t.TID
) AS b
WHERE a.TID IS NULL OR b.TID IS NULL
ORDER BY a.lName, b.docNumber

example results:

lName     fName  docNumber          docName
Simpson   Homer     1      Nuclear Physics for Dummies
Simpson   Homer     2      Nuclear Physics for Beginners
Simpson   Homer     3      Advanced Nuclear Physics
Simpson   Lisa      3      Advanced Nuclear Physics

Upvotes: 6

Larry Lustig
Larry Lustig

Reputation: 50998

Okay, you have to JOIN all three tables with the trainingRecords table in the middle because it has the columns necessary to link the other two tables. Your query will look something like this:

 SELECT E.lName, E.fName, ML.docName, ML.docNumber FROM
   (employees E LEFT OUTER JOIN trainingRecords TR ON E.empID = TR.empID)
                RIGHT OUTER JOIN masterList ML ON ML.TID = TR.TID
   WHERE TR.TID IS NULL

What's happening here?

First, you're doing a LEFT OUTER JOIN of employees and trainingRecords. The LEFT OUTER is to ensure that all the records from employees show up even if there's no match in trainingRecords (which of course don't exist since trainingRecords has no data at all).

Then, you're taking the results of that query and RIGHT OUTER JOINing them to masterList. The RIGHT OUTER guarantees that all masterList records will be included even if there are no matches in trainingRecords.

Finally, WHERE TR.TID IS NULL filters out any records that actually matched any (future) records in trainingRecords.

Upvotes: 0

Suroot
Suroot

Reputation: 4423

You want LEFT JOIN, on the left side of the join will be the table that you know will contain everything and on the right will be what you are testing against.

select masterList.* from masterList LEFT JOIN trainingRecords ON(masterList.TID = trainingRecords.TID) WHERE trainingRecords.TID IS NULL; 

Upvotes: 3

Related Questions