开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜