MySQL两SELECT子查询使用!=连接未返回预期空结果原因
问题原因
你当前的写法用了逗号分隔的隐式交叉连接(笛卡尔积),会先生成两个子查询结果的笛卡尔积,再做条件过滤,和你预期的逻辑完全不符:
- 你的两个子查询各返回2条数据,交叉后会生成2*2=4条匹配记录:
- 前期学生1196 匹配 当日学生1196
- 前期学生1196 匹配 当日学生1861
- 前期学生1861 匹配 当日学生1196
- 前期学生1861 匹配 当日学生1861
- 你写的
prev_student.student_id != today_student.student_id条件,只会过滤掉上面4条里id完全相等的2条记录,剩下的2条交叉结果会正常返回,根本不是你要的「当日缴费的学生,在前期时间段完全没有缴费记录」的判断逻辑。
你需要的是反连接逻辑:筛选出当日学生集合中,学生ID完全不存在于前期学生集合的记录,而不是逐行交叉后判断单行ID不相等。
修正方案
两种常用写法都能实现你的需求,按当前测试数据都会返回空结果集:
方案1:NOT IN 实现
SELECT today_student.* FROM ( SELECT scd.student_id, sc.transaction_date FROM student_collection_details scd INNER JOIN student_collection sc ON scd.student_collection_id = sc.id WHERE sc.transaction_date = DATE('2022-06-28 00:00:00') AND scd.admission_year_id = 2 AND scd.month_id = 21 AND scd.collection_head_id = 9 GROUP BY scd.student_id ) today_student WHERE today_student.student_id NOT IN ( SELECT scd.student_id FROM student_collection_details scd INNER JOIN student_collection sc ON scd.student_collection_id = sc.id WHERE sc.transaction_date BETWEEN DATE('2022-06-01 00:00:00') AND DATE('2022-06-27 00:00:00') AND scd.admission_year_id = 2 AND scd.month_id = 21 AND scd.collection_head_id = 9 GROUP BY scd.student_id );
方案2:LEFT JOIN 反连接实现
SELECT today_student.* FROM ( SELECT scd.student_id, sc.transaction_date FROM student_collection_details scd INNER JOIN student_collection sc ON scd.student_collection_id = sc.id WHERE sc.transaction_date = DATE('2022-06-28 00:00:00') AND scd.admission_year_id = 2 AND scd.month_id = 21 AND scd.collection_head_id = 9 GROUP BY scd.student_id ) today_student LEFT JOIN ( SELECT scd.student_id FROM student_collection_details scd INNER JOIN student_collection sc ON scd.student_collection_id = sc.id WHERE sc.transaction_date BETWEEN DATE('2022-06-01 00:00:00') AND DATE('2022-06-27 00:00:00') AND scd.admission_year_id = 2 AND scd.month_id = 21 AND scd.collection_head_id = 9 GROUP BY scd.student_id ) prev_student ON today_student.student_id = prev_student.student_id WHERE prev_student.student_id IS NULL;
注:如果前期子查询的student_id可能存在NULL值,不要用NOT IN写法,会出现判断逻辑失效的问题,优先选LEFT JOIN反连接写法。
内容的提问来源于stack exchange,提问作者Sumon Bappi
相关产品推荐
相关产品推荐

