Reputation: 30993
I have a schema like this:
// table badge_types
id | name
+++|++++++++++
1 | mentor
2 | proctor
3 | doctor
// table badges
id | badge_type_id | user_id
+++|+++++++++++++++|++++++++
1 | 1 | 5
2 | 1 | 6
3 | 2 | 6
4 | 3 | 6
5 | 2 | 19
6 | 3 | 20
What I want to do, is select all badge_types
that a particular user has not yet gotten. In the above example, calling the query for:
user_id = 5
returns badge_type_id
2
and 3
user_id = 6
returns empty
set (user got all of them already)
user_id = 19
returns badge_type_id
1
and 3
I can do this with an INTERSECT
clause. But I'm wondering if it can be done with a simple JOIN
? Any help would be appreciated.
Upvotes: 2
Views: 2057
Reputation: 332581
SELECT bt.name
FROM BADGE_TYPES bt
LEFT JOIN BAGDES b ON b.badge_type_id = bt.id
AND b.user_id = ?
WHERE b.id IS NULL
SELECT bt.name
FROM BADGE_TYPES bt
WHERE NOT EXISTS(SELECT NULL
FROM BADGES b
WHERE b.badge_type_id = bt.id
AND b.user_id = ?)
SELECT bt.name
FROM BADGE_TYPES bt
WHERE bt.id NOT IN (SELECT b.badge_type_id
FROM BADGES b
WHERE b.user_id = ?)
If the columns are not nullable, LEFT JOIN/IS NULL is the best choice. If they are nullable, NOT EXISTS
and NOT IN
are the best choice.
Upvotes: 13