MySQL查询:获取满足用户条件的首个记录数≤5的日期(含无记录日期)
MySQL查询:获取满足用户条件的首个记录数≤5的日期(含无记录日期)
我完全懂你的需求——你要从指定的起始日期(这里是2023-03-14)开始,找到第一个该用户的记录数不超过5的日期,包括那些完全没有该用户记录的日期(这时候记录数是0,肯定满足≤5的要求)。你当前的查询只筛选出了有该用户记录的日期,所以直接漏掉了2023-03-14这个符合条件的日期。
问题出在:你的原查询只统计了表中存在该用户数据的日期,而那些没有数据的日期根本不会出现在结果里,自然没法被选中。要解决这个问题,我们需要先生成一段连续的日期序列,再把用户的记录数据关联上去,这样就能覆盖到无记录的日期了。
解决方案(MySQL 8.0+ 版本,支持递归CTE)
用递归CTE生成从起始日期开始的连续日期,再左连接用户表统计每个日期的记录数:
WITH RECURSIVE date_range AS ( -- 定义起始日期 SELECT '2023-03-14' AS check_date UNION ALL -- 生成后续的连续日期,这里可以调整结束条件,比如生成未来7天 SELECT DATE_ADD(check_date, INTERVAL 1 DAY) FROM date_range WHERE check_date < '2023-03-20' -- 可以设一个合理的结束日期,避免无限递归 ) SELECT COALESCE(COUNT(uq.id), 0) AS cnt, dr.check_date AS scheduled_at FROM date_range dr LEFT JOIN estudojo.user_scheduled_questions uq ON dr.check_date = uq.scheduled_at AND uq.user_id = '1' -- 提前过滤用户,避免全表扫描 GROUP BY dr.check_date HAVING cnt <= 5 ORDER BY dr.check_date ASC LIMIT 1;
这段代码的逻辑:
date_range递归生成从2023-03-14开始的连续日期,确保我们要检查的日期都被包含。- 左连接用户表,这样即使某个日期没有该用户的记录,也会保留这个日期。
COALESCE把NULL的计数转为0,让无记录的日期显示cnt=0。- 最后按日期升序排序,取第一个满足cnt≤5的结果,就是你要的2023-03-14。
兼容MySQL 5.x版本的方案(不支持递归CTE)
如果你的MySQL版本比较旧,可以用数字表来生成日期范围:
SELECT COALESCE(COUNT(uq.id), 0) AS cnt, DATE_ADD('2023-03-14', INTERVAL n.n DAY) AS scheduled_at FROM ( -- 生成0-6的数字,对应7天的日期范围,可按需扩展 SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 ) n LEFT JOIN estudojo.user_scheduled_questions uq ON DATE_ADD('2023-03-14', INTERVAL n.n DAY) = uq.scheduled_at AND uq.user_id = '1' GROUP BY scheduled_at HAVING cnt <=5 ORDER BY scheduled_at ASC LIMIT 1;
这样执行后,就能得到你期望的结果:
┌─────────┬─────┬─────────────────────────────┐ │ (index) │ cnt │ scheduled_at │ ├─────────┼─────┼─────────────────────────────┤ │ 0 │ 0 │ '2023-03-14' │ └─────────┴─────┴─────────────────────────────┘
备注:内容来源于stack exchange,提问作者Gabriel Cunha
相关产品推荐
相关产品推荐

