如何在MySQL多对多关系中判断记录是否不存在?
在MySQL多对多关系中判断记录不存在的几种实用方法
嘿,针对你开发选择题答题应用时遇到的多对多关系记录存在性判断问题,我整理了几个常用且靠谱的方案,结合你的场景(比如用户和已答题目之间的关联)来举例说明:
1. LEFT JOIN + IS NULL 方法
这是最经典的写法之一,逻辑直观:通过左连接关联中间表,筛选出那些在中间表中没有匹配记录的数据。
假设你的应用里有三张表:
users:用户表(已有你的user_id等字段)questions:选择题表(比如包含question_id、content等)user_question_answers:用户答题记录表(多对多中间表,包含user_id、question_id、answer等字段)
如果要判断用户ID为123的用户是否没答过题目ID为456的题,可以这么写:
SELECT q.question_id, q.content FROM questions q LEFT JOIN user_question_answers uqa ON q.question_id = uqa.question_id AND uqa.user_id = 123 WHERE q.question_id = 456 AND uqa.user_id IS NULL;
如果查询结果有数据,说明该用户没答过这道题;反之则已经答过。
要是想找出某个用户所有未答的题目,去掉WHERE q.question_id = 456即可:
SELECT q.question_id, q.content FROM questions q LEFT JOIN user_question_answers uqa ON q.question_id = uqa.question_id AND uqa.user_id = 123 WHERE uqa.user_id IS NULL;
2. NOT EXISTS 子查询方法
这个方法的语义更贴合“不存在”的需求,可读性强,而且当中间表的user_id和question_id有联合索引时,性能表现优异。
同样判断用户123是否没答过题目456:
SELECT q.question_id, q.content FROM questions q WHERE q.question_id = 456 AND NOT EXISTS ( SELECT 1 FROM user_question_answers uqa WHERE uqa.user_id = 123 AND uqa.question_id = q.question_id );
子查询会检查是否存在该用户对这道题的答题记录,NOT EXISTS就表示不存在的情况。
3. NOT IN 方法(需谨慎使用)
这个写法简洁,但要注意一个坑:如果子查询的结果中包含NULL值,NOT IN会返回空结果,所以只有当你能确保子查询不会出现NULL时才建议用。
比如判断用户123未答的题目:
SELECT q.question_id, q.content FROM questions q WHERE q.question_id NOT IN ( SELECT uqa.question_id FROM user_question_answers uqa WHERE uqa.user_id = 123 AND uqa.question_id IS NOT NULL -- 显式排除NULL,避免踩坑 );
小提示
- 优先推荐
NOT EXISTS或LEFT JOIN + IS NULL,它们的性能更稳定,也不容易踩NULL的坑; - 记得给中间表的联合字段(比如
user_id和question_id)创建联合索引,能大幅提升查询速度,尤其是数据量较大的时候。
内容的提问来源于stack exchange,提问作者hotmeatballsoup
相关产品推荐
相关产品推荐

