使用JOIN而不是INTERSECT进行查询

时间:2010-07-23 00:11:41

标签: sql mysql database

我有这样的架构:

// 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

我想要做的是选择特定用户尚未获得的所有badge_types。在上面的示例中,调用查询:

user_id = 5返回badge_type_id 23

user_id = 6返回empty设置(用户已获得所有这些)

user_id = 19返回badge_type_id 13

我可以使用INTERSECT子句执行此操作。但我想知道是否可以用简单的JOIN来完成它?任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:13)

使用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

使用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 = ?)

使用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

如果列是not nullable, LEFT JOIN/IS NULL is the best choice。如果他们are nullable, NOT EXISTS and NOT IN are the best choice

SQL Server

请注意on SQL Server, NOT IN and NOT EXISTS perform better than LEFT JOIN /IS NULL if the columns in question are not nullable

的Oracle

Oracle, all three are equivalent but LEFT JOIN/IS NULL and NOT EXISTS are preferable if columns aren't nullable