You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL 8.0.21中拆分日期范围为月度记录(SQL新手求助)

解决MySQL中日期范围拆分为月度记录的问题

嗨,作为SQL新手遇到这种需求确实有点懵,不过好在你的MySQL版本是8.0.21,支持递归CTE(公共表表达式),这刚好是处理这类连续序列生成问题的最佳方案。我直接给你可运行的SQL代码,再帮你拆解下逻辑:

实现代码

WITH RECURSIVE month_range AS (
    -- 锚点查询:获取初始记录的基础信息和第一个月份
    SELECT 
        name,
        course,
        DATE_FORMAT(sdate, '%Y-%m') AS enrollMonth,
        edate
    FROM your_table_name  -- 记得替换成你实际的表名
    UNION ALL
    -- 递归查询:逐月生成后续月份,直到覆盖到结束日期所在月份
    SELECT 
        name,
        course,
        DATE_FORMAT(DATE_ADD(STR_TO_DATE(enrollMonth, '%Y-%m'), INTERVAL 1 MONTH), '%Y-%m'),
        edate
    FROM month_range
    -- 终止条件:当前生成的月份不晚于结束日期所在的月份
    WHERE STR_TO_DATE(enrollMonth, '%Y-%m') <= DATE_SUB(edate, INTERVAL DAY(edate)-1 DAY)
)
-- 最终取出需要的字段并按月份排序
SELECT name, course, enrollMonth
FROM month_range
ORDER BY enrollMonth;

代码逻辑解释

  • 递归CTE的结构:WITH RECURSIVE是MySQL 8.0引入的特性,允许我们通过“锚点+递归”的方式生成连续数据。
  • 锚点部分:先从你的表中取出原始记录,用DATE_FORMAT把sdate转换成YYYY-MM格式的月份,同时保留edate用来判断什么时候停止递归。
  • 递归部分:每次把上一轮生成的enrollMonth转成日期后,加一个月再转回YYYY-MM格式,这样就能得到下一个月份。
  • 终止条件:DATE_SUB(edate, INTERVAL DAY(edate)-1 DAY)的作用是获取edate所在月份的第一天(比如2019-11-20会变成2019-11-01),只要当前生成的月份不晚于这个日期,就继续递归,这样就能确保包含结束日期所在的整个月份。

这个方案不仅能处理单条记录,如果你表中有多条不同的培训记录,它也能自动为每条记录拆分出对应的月度数据,非常灵活。

内容的提问来源于stack exchange,提问作者Tanzeel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 12:02:51