MySQL查询近3个月数据返回异常,寻求技术排查方案
解决MySQL查询最近3个月数据的问题
先帮你捋捋当前查询的问题:你写的last_day(now()) + INTERVAL 1 day - INTERVAL 3 month这个条件,其实是在计算当前月的第一天往前推3个月的第一天(举个例子,如果现在是2024年5月,这个表达式算出来的是2024-03-01),所以只会筛选出3月1日及以后的数据。你的表只有1月和5月的数据,那1月的记录早于3月1日,自然会被过滤掉,最终只能返回5月的汇总结果。
下面根据不同的需求场景,给你对应的解决方案:
场景1:要查过去3个自然月(包含当前月)的数据,没数据的月份显示0
如果你希望拿到最近3个完整的自然月(比如当前5月,就要3、4、5月),哪怕某个月没有预约记录,也要显示该月的total为0,那可以用递归CTE生成月份序列,再和你的表做左连接:
-- 先生成最近3个月的起始日期序列 WITH RECURSIVE months AS ( SELECT DATE_FORMAT(CURDATE() - INTERVAL 2 MONTH, '%Y-%m-01') AS month_start UNION ALL SELECT DATE_ADD(month_start, INTERVAL 1 MONTH) FROM months WHERE month_start < DATE_FORMAT(CURDATE(), '%Y-%m-01') ) SELECT MONTH(m.month_start) AS month, COALESCE(SUM(a.service_price), 0) AS total FROM months m LEFT JOIN appointments a ON a.user_id = 1 AND a.service_date_time >= m.month_start AND a.service_date_time < DATE_ADD(m.month_start, INTERVAL 1 MONTH) GROUP BY YEAR(m.month_start), MONTH(m.month_start) ORDER BY m.month_start;
这个查询会自动生成最近3个月的每个月第一天,然后左连接预约表统计金额,没有数据的月份用COALESCE把NULL转换成0。
场景2:要查过去90天(滚动式的3个月)的数据
如果你的“最近3个月”是指从今天往前推90天的滚动时间段(不是严格的自然月),那条件可以简化成这样:
SELECT MONTH(service_date_time) AS month, SUM(service_price) AS total FROM appointments WHERE user_id = 1 AND service_date_time >= CURDATE() - INTERVAL 3 MONTH GROUP BY YEAR(service_date_time), MONTH(service_date_time) ORDER BY YEAR(service_date_time), MONTH(service_date_time);
比如今天是2024-05-20,这个条件会筛选出2024-02-20到2024-05-20之间的所有记录,然后按月份汇总。
场景3:要查最近3个有数据的月份(不管时间跨度)
如果你的需求是找出该用户在表中最近的3个有预约记录的月份(比如你的表有1月、5月的数据,当前是5月,那就是5月;如果还有4月的数据,就是5、4、1月这样按时间倒序的前3个),可以用下面的查询:
SELECT MONTH(service_date_time) AS month, SUM(service_price) AS total FROM appointments WHERE user_id = 1 AND CONCAT(YEAR(service_date_time), '-', MONTH(service_date_time)) IN ( SELECT DISTINCT CONCAT(YEAR(service_date_time), '-', MONTH(service_date_time)) FROM appointments WHERE user_id = 1 ORDER BY service_date_time DESC LIMIT 3 ) GROUP BY YEAR(service_date_time), MONTH(service_date_time) ORDER BY YEAR(service_date_time) DESC, MONTH(service_date_time) DESC;
子查询会先找出该用户最近3个有数据的月份,外层查询再统计这些月份的总金额。
内容的提问来源于stack exchange,提问作者James Ramputh




