Query using JOIN instead of INTERSECT
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 th开发者_运维百科e 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.
Using LEFT JOIN/IS NULL:
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
Using NOT EXISTS
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 = ?)
Using NOT IN
SELECT bt.name
FROM BADGE_TYPES bt
WHERE bt.id NOT IN (SELECT b.badge_type_id
FROM BADGES b
WHERE b.user_id = ?)
MySQL
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.
SQL Server
Mind that on SQL Server, NOT IN
and NOT EXISTS
perform better than LEFT JOIN /IS NULL if the columns in question are not nullable.
Oracle
For Oracle, all three are equivalent but LEFT JOIN/IS NULL and NOT EXISTS are preferable if columns aren't nullable.
精彩评论