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

如何在SQL Server(T-SQL)中实现月末最后3个工作日转下月的逻辑?

解决T-SQL中判断当月最后3个工作日并切换月份的需求

这个需求的核心是先识别输入日期是否属于当月最后3个工作日,再决定是否切换到下月的年月格式(YYYYMM)。下面是具体的实现方案,兼容SQL Server 2012及以上版本:

方案1:创建标量函数(可复用)

这个函数可以直接传入日期,返回目标年月,适合在多个查询中重复调用:

CREATE FUNCTION dbo.GetTargetMonth (@InputDate DATE)
RETURNS VARCHAR(6)
AS
BEGIN
    -- 显式设置周日为一周第一天,避免环境DATEFIRST差异影响判断
    SET DATEFIRST 7;

    DECLARE @LastDayOfMonth DATE = EOMONTH(@InputDate);
    
    -- 计算当月最后1个工作日
    DECLARE @LastWorkDay1 DATE = 
        CASE DATEPART(WEEKDAY, @LastDayOfMonth)
            WHEN 1 THEN DATEADD(DAY, -2, @LastDayOfMonth) -- 最后一天是周日,往前推2天到周五
            WHEN 7 THEN DATEADD(DAY, -1, @LastDayOfMonth) -- 最后一天是周六,往前推1天到周五
            ELSE @LastDayOfMonth -- 最后一天是工作日,直接用
        END;
    
    -- 计算当月倒数第2个工作日
    DECLARE @LastWorkDay2 DATE = 
        CASE DATEPART(WEEKDAY, DATEADD(DAY, -1, @LastWorkDay1))
            WHEN 1 THEN DATEADD(DAY, -2, DATEADD(DAY, -1, @LastWorkDay1))
            WHEN 7 THEN DATEADD(DAY, -1, DATEADD(DAY, -1, @LastWorkDay1))
            ELSE DATEADD(DAY, -1, @LastWorkDay1)
        END;
    
    -- 计算当月倒数第3个工作日
    DECLARE @LastWorkDay3 DATE = 
        CASE DATEPART(WEEKDAY, DATEADD(DAY, -1, @LastWorkDay2))
            WHEN 1 THEN DATEADD(DAY, -2, DATEADD(DAY, -1, @LastWorkDay2))
            WHEN 7 THEN DATEADD(DAY, -1, DATEADD(DAY, -1, @LastWorkDay2))
            ELSE DATEADD(DAY, -1, @LastWorkDay2)
        END;
    
    -- 判断输入日期是否属于最后3个工作日
    DECLARE @IsLastThreeWorkDays BIT = 
        CASE WHEN @InputDate BETWEEN @LastWorkDay3 AND @LastWorkDay1 THEN 1 ELSE 0 END;
    
    -- 返回目标年月:满足条件则返回下月,否则返回当月
    RETURN CASE @IsLastThreeWorkDays
        WHEN 1 THEN FORMAT(DATEADD(MONTH, 1, @InputDate), 'yyyyMM')
        ELSE FORMAT(@InputDate, 'yyyyMM')
    END;
END;

测试你的示例

执行以下查询验证结果:

SELECT dbo.GetTargetMonth('20180627') AS TargetMonth; -- 输出:201807
SELECT dbo.GetTargetMonth('20180529') AS TargetMonth; -- 输出:201806
SELECT dbo.GetTargetMonth('20190226') AS TargetMonth; -- 输出:201903
SELECT dbo.GetTargetMonth('20181227') AS TargetMonth; -- 输出:201901

方案2:单查询实现(无需创建函数)

如果只是一次性使用,可以用CTE(公共表表达式)把逻辑整合到单个查询中:

DECLARE @InputDate DATE = '20180627';
SET DATEFIRST 7; -- 统一日期判断规则

WITH LastWorkDays AS (
    SELECT 
        EOMONTH(@InputDate) AS LastDayOfMonth,
        CASE DATEPART(WEEKDAY, EOMONTH(@InputDate))
            WHEN 1 THEN DATEADD(DAY, -2, EOMONTH(@InputDate))
            WHEN 7 THEN DATEADD(DAY, -1, EOMONTH(@InputDate))
            ELSE EOMONTH(@InputDate)
        END AS LastWorkDay1
),
LastWorkDays2 AS (
    SELECT 
        LastDayOfMonth,
        LastWorkDay1,
        CASE DATEPART(WEEKDAY, DATEADD(DAY, -1, LastWorkDay1))
            WHEN 1 THEN DATEADD(DAY, -2, DATEADD(DAY, -1, LastWorkDay1))
            WHEN 7 THEN DATEADD(DAY, -1, DATEADD(DAY, -1, LastWorkDay1))
            ELSE DATEADD(DAY, -1, LastWorkDay1)
        END AS LastWorkDay2
),
LastWorkDays3 AS (
    SELECT 
        LastDayOfMonth,
        LastWorkDay1,
        LastWorkDay2,
        CASE DATEPART(WEEKDAY, DATEADD(DAY, -1, LastWorkDay2))
            WHEN 1 THEN DATEADD(DAY, -2, DATEADD(DAY, -1, LastWorkDay2))
            WHEN 7 THEN DATEADD(DAY, -1, DATEADD(DAY, -1, LastWorkDay2))
            ELSE DATEADD(DAY, -1, LastWorkDay2)
        END AS LastWorkDay3
)
SELECT 
    CASE WHEN @InputDate BETWEEN LastWorkDay3 AND LastWorkDay1
         THEN FORMAT(DATEADD(MONTH, 1, @InputDate), 'yyyyMM')
         ELSE FORMAT(@InputDate, 'yyyyMM')
    END AS TargetMonth
FROM LastWorkDays3;

注意事项

  • 节假日处理:以上逻辑只排除了周六和周日,如果需要考虑法定节假日,你需要额外维护一个节假日表,在判断工作日时加入对该表的查询。
  • SQL Server版本:EOMONTH()和FORMAT()函数从SQL Server 2012开始支持,如果是更早版本,需要用DATEADD(DAY, -DAY(@InputDate), DATEADD(MONTH, 1, @InputDate))替代EOMONTH(),用CONVERT(VARCHAR(6), @Date, 112)替代FORMAT()来生成YYYYMM格式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:53:49