This isn't a join at all.
The statement is filtering only records for teachers who don't have an assigned department.
Set Difference
The set difference of teachers and departments, teacher \ department
would be a kind of "anti-join"
SELECT
t.name
FROM teacher t
LEFT JOIN department d ON d.id = t.dept_id
WHERE d.id IS NULL
At first glance, this statement does what your statement does, if the foreign key reference was enforced, it would guarantee to do exactly that. However, one use for this statement would be to retrieve teachers who are assigned to departments that have since been deleted (e.g. if the English Lit Dept. & English as 2nd Lang Dept. were reorganized as the English Dept.)
Symmetric Difference
Another "anti-join" would be the symmetric difference, which selects elements from both sets ONLY if they cannot be joined, i.e
(teacher \ department) U (department \ teacher)
I can't think of a motivating example using teachers and departments, but one way to write the symmetric difference on databases that support the FULL OUTER JOIN would be:
SELECT
t.name
FROM teacher t
FULL OUTER JOIN department d ON d.id = t.dept_id
WHERE d.id IS NULL OR t.id IS NULL
For MySQL, this statement would have to be written as the union of two statements.
SELECT
t.name teacher_name, d.name department_name
FROM teacher t
LEFT JOIN department d ON d.id = t.dept_id
WHERE d.id IS NULL
UNION ALL
SELECT
t.name teacher_name, d.name department_name
FROM teacher t
LEFT JOIN department d ON d.id = t.dept_id
WHERE t.id IS NULL
Looking through one of my projects, I found this one use of symmetric difference:
Context:
I have three tables: users
, users_gameplay_summary
, users_transactions_summary
. I needed to email those users who created their accounts in the past 7 days AND one of the following
have transacted but have not played
or played but have not transacted.
To get the list, I have this query (note, this was written for Postgresql, and won't work on MySQL, but it illustrates the symmetric difference use case):
SELECT
COALESCE(g.user_id, t.user_id) user_id
FROM users_gameplay_summary g
FULL OUTER JOIN users_transactions_summary t ON t.user_id = g.user_id
WHERE COALESCE(g.user_id, t.user_id) IN (
SELECT user_id
FROM users
WHERE created_at > CURRENT_DATE - '7 day'::interval)
AND (g.user_id IS NULL OR t.user_id IS NULL)