atp*_*atp 2 mysql sql 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
Run Code Online (Sandbox Code Playgroud)
我想要做的是选择badge_types特定用户尚未获得的所有内容.在上面的示例中,调用查询:
user_id = 5回归badge_type_id 2和3
user_id = 6返回empty集(用户已经获得所有这些)
user_id = 19回归badge_type_id 1和3
我可以用一个INTERSECT条款做到这一点.但我想知道它是否可以通过简单的方式完成JOIN?任何帮助,将不胜感激.
OMG*_*ies 13
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
Run Code Online (Sandbox Code Playgroud)
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 = ?)
Run Code Online (Sandbox Code Playgroud)
SELECT bt.name
FROM BADGE_TYPES bt
WHERE bt.id NOT IN (SELECT b.badge_type_id
FROM BADGES b
WHERE b.user_id = ?)
Run Code Online (Sandbox Code Playgroud)
如果列不可为空,则LEFT JOIN/IS NULL是最佳选择.如果它们是空的,NOT EXISTS并且NOT IN是最好的选择.
心说SQL Server上,NOT IN并NOT EXISTS有更好的表现比LEFT JOIN如果有问题的字段不可为空/ IS NULL.
对于Oracle,所有三个都是等效的,但如果列不可为空,则优选LEFT JOIN/IS NULL和NOT EXISTS.