MySQL:通过关联查询获取不在另一表中的记录
没问题,我来帮你搞定这类「查询不在另一张表中记录」的需求!先咱们先把你的四张表结构明确下来,方便后续写SQL的时候对照:
-- categories(分类表) id | name ------------------ 1 | category 1 2 | category 2 3 | category 3 4 | category 4 5 | category 5 6 | category 6 -- countries(国家表) id | name ------------------ 1 | country 1 2 | country 2 3 | country 3 4 | country 4 5 | country 5 6 | country 6 -- users(用户表) id | name | country_id ------------------------------- 1 | john doe 1 | 1 2 | john doe 2 | 2 3 | john doe 3 | 3 4 | john doe 4 | 4 5 | john doe 5 | 4 6 | john doe 6 | 5 -- users_categories(用户分类关联表) id | category_id | user_id
下面针对几种常见的「不在另一张表」的查询场景,给出具体的SQL实现和逻辑说明:
场景1:查询没有关联任何分类的用户
也就是找出users表中,从未出现在users_categories关联表中的用户,有三种常用写法:
方法1:LEFT JOIN + IS NULL(直观易懂)
SELECT u.id, u.name, u.country_id FROM users u LEFT JOIN users_categories uc ON u.id = uc.user_id WHERE uc.user_id IS NULL;
逻辑:用左连接把用户和关联表绑定,关联表中没有匹配记录的用户,对应的uc.user_id会是NULL,筛选这些结果就是目标用户。
方法2:NOT EXISTS(大数据量下性能更优)
SELECT u.id, u.name, u.country_id FROM users u WHERE NOT EXISTS ( SELECT 1 FROM users_categories uc WHERE uc.user_id = u.id );
逻辑:子查询检查当前用户是否在关联表中有记录,NOT EXISTS会直接返回没有匹配的用户。这种写法在数据量大时通常比NOT IN更快,而且不会因为关联表存在NULL值导致异常。
方法3:NOT IN(注意避坑)
SELECT u.id, u.name, u.country_id FROM users u WHERE u.id NOT IN ( SELECT uc.user_id FROM users_categories uc WHERE uc.user_id IS NOT NULL -- 必须过滤NULL,否则结果为空 );
逻辑:提取关联表中所有用户ID,然后筛选不在这个列表里的用户。注意:如果users_categories的user_id存在NULL,NOT IN会直接返回空结果,所以一定要加WHERE uc.user_id IS NOT NULL。
场景2:查询没有被任何用户关联的分类
和场景1逻辑相反,找出categories表中从未被关联的分类:
-- LEFT JOIN写法 SELECT c.id, c.name FROM categories c LEFT JOIN users_categories uc ON c.id = uc.category_id WHERE uc.category_id IS NULL; -- NOT EXISTS写法(推荐) SELECT c.id, c.name FROM categories c WHERE NOT EXISTS ( SELECT 1 FROM users_categories uc WHERE uc.category_id = c.id );
场景3:查询不在指定国家的用户
比如要找出所有不在「country 4」的用户,或者不在某几个国家列表里的用户:
-- 直接通过country_id筛选 SELECT u.id, u.name, u.country_id FROM users u WHERE u.country_id != 4; -- 筛选不在多个国家的用户(比如country 1和country 2) SELECT u.id, u.name, u.country_id FROM users u WHERE u.country_id NOT IN (1, 2); -- 关联countries表,通过国家名称筛选 SELECT u.id, u.name, u.country_id, c.name AS country_name FROM users u JOIN countries c ON u.country_id = c.id WHERE c.name != 'country 4';
内容的提问来源于stack exchange,提问作者Ricardo Santos
相关产品推荐
相关产品推荐

