MySQL查询异常:用户完成单个任务后无法加载其余可做任务
问题分析与解决方案
你的查询逻辑存在核心问题,导致用户完成任意一个任务后就看不到其他可执行任务了——NOT EXISTS子查询没有关联到外层的具体任务,它错误地检查了用户是否存在任何已完成任务,而非当前任务是否被该用户完成。
原查询的关键问题
原查询里的NOT EXISTS子查询:
SELECT mid , uid FROM missions_progress mp WHERE uid = {$uid} AND mstatus = 'completed'
这里有两个致命问题:
- 子查询的
mp别名和外层的missions_progress mp重名,极易造成逻辑混淆 - 没有关联外层任务的ID,导致只要用户有过任意一条已完成任务记录,这个子查询就会返回结果,NOT EXISTS条件直接不成立,最终整个查询返回空数据
修正后的查询代码
我们需要让NOT EXISTS精准检查当前任务是否被该用户完成,修正后的查询如下:
SELECT mp.*, m.* FROM missions m LEFT JOIN missions_progress mp ON mp.mid = m.id AND mp.uid = {$uid} WHERE NOT EXISTS ( SELECT 1 FROM missions_progress mp_sub WHERE mp_sub.mid = m.id AND mp_sub.uid = {$uid} AND mp_sub.mstatus = 'completed' )
逻辑说明
- 从
missions表出发遍历所有任务(因为我们要展示所有用户可执行的任务,不管用户是否已经开始) - LEFT JOIN时直接关联当前用户的任务进度,能同时拿到用户对该任务的现有进度(如果有的话)
- NOT EXISTS子查询明确绑定当前任务的
m.id,只检查该用户是否没有完成这个任务——只有当用户不存在该任务的completed记录时,才会把这个任务加入结果列表
额外优化提示
- 给子查询的表使用独立别名(比如
mp_sub),避免和外层表混淆,提升代码可读性 - 子查询无需返回具体字段,用
SELECT 1即可,数据库会自动优化这类查询,性能更优 - 如果你的需求是“排除用户已开始但未完成的任务”,可以在WHERE条件里额外添加
mp.id IS NULL来筛选出用户完全未接触的任务
内容的提问来源于stack exchange,提问作者Love2Code
相关产品推荐
相关产品推荐

