MySQL排除周末的日期加法问题(现有方案存在局限)
嗨,我完全懂你的痛点!那些只处理单个周末的SQL片段在遇到跨多个周末的场景时确实会失效,毕竟现实中我们经常需要计算几十甚至上百个工作日后的日期。
解决方案1:递归CTE(直观且准确,适合中小数据量)
递归CTE的思路很直接:逐个累加/递减日期,遇到周末直接跳过,直到完成指定的工作日数。这种方法不管跨多少个周末都能准确计算,而且逻辑容易理解。
下面是支持正负天数的通用查询(正数加工作日,负数减工作日):
WITH RECURSIVE date_calculator AS ( SELECT StartDate AS current_date, ExpectedDate AS remaining_days FROM your_table UNION ALL SELECT -- 根据剩余天数的正负,决定是加还是减日期,同时跳过周末 CASE WHEN remaining_days > 0 THEN -- 加工作日:如果当前是周五,直接跳到下周一(加3天),否则加1天 CASE WEEKDAY(current_date) WHEN 4 THEN DATE_ADD(current_date, INTERVAL 3 DAY) ELSE DATE_ADD(current_date, INTERVAL 1 DAY) END ELSE -- 减工作日:如果当前是周一,直接跳到上周五(减3天),否则减1天 CASE WEEKDAY(current_date) WHEN 0 THEN DATE_SUB(current_date, INTERVAL 3 DAY) ELSE DATE_SUB(current_date, INTERVAL 1 DAY) END END, -- 更新剩余天数:正数减1,负数加1,直到归0 remaining_days + CASE WHEN remaining_days > 0 THEN -1 ELSE 1 END FROM date_calculator WHERE remaining_days != 0 ) SELECT StartDate, ExpectedDate, current_date AS FinalDate FROM date_calculator WHERE remaining_days = 0;
解决方案2:数学公式法(高效,适合大数据量)
如果你的数据量很大,递归可能会有性能问题,这时可以用数学公式直接计算需要调整的周末天数,避免循环。核心是计算起始日期到目标日期区间内包含的完整周末数,再加上边界的周末调整。
下面是支持正负天数的公式:
SELECT StartDate, ExpectedDate, CASE WHEN ExpectedDate = 0 THEN StartDate ELSE DATE_ADD( StartDate, INTERVAL ExpectedDate -- 计算完整的周末数量:每5个工作日对应2个周末 + 2 * FLOOR((ABS(ExpectedDate) + WEEKDAY(StartDate) + (ExpectedDate < 0)) / 5) -- 调整边界情况:如果起始日期加工作日后跨到周末,额外加2天(加的情况)或减2天(减的情况) + CASE WHEN ExpectedDate > 0 AND (WEEKDAY(StartDate) + ExpectedDate) % 5 >= 5 THEN 2 WHEN ExpectedDate < 0 AND (WEEKDAY(StartDate) + ExpectedDate) % 5 < 0 THEN -2 ELSE 0 END DAY ) END AS FinalDate FROM your_table;
针对你的特殊场景(加自然天后跳过周末)
如果你的需求是加N个自然天后,若结果为周末则自动跳至下一个工作日(比如你例子中2018-01-08加20自然天是周日,跳至2018-01-29),可以用这个简化查询:
SELECT StartDate, ExpectedDate, CASE WHEN WEEKDAY(DATE_ADD(StartDate, INTERVAL ExpectedDate DAY)) IN (5,6) THEN DATE_ADD( DATE_ADD(StartDate, INTERVAL ExpectedDate DAY), INTERVAL CASE WEEKDAY(DATE_ADD(StartDate, INTERVAL ExpectedDate DAY)) WHEN 5 THEN 2 WHEN 6 THEN 1 END DAY ) ELSE DATE_ADD(StartDate, INTERVAL ExpectedDate DAY) END AS FinalDate FROM your_table;
这几种方案都能解决你之前遇到的“多个周末无法正确计算”的问题,你可以根据自己的业务场景选择合适的方法。
内容的提问来源于stack exchange,提问作者pipechaves
相关产品推荐
相关产品推荐

