给定日期所在月份首个周一的SQL查询是否有效?有无更优方案?
问题解答
原SQL语句不符合预期
你的SQL逻辑存在问题,它返回的是当月第一天之前最近的周一(可能属于上月),而非当月内的首个周一。举个实际例子:
假设给定日期是2024年3月15日,当月第一天是3月1日(周五,按你的配置DATEPART(WEEKDAY)返回5),代入计算后得到的是2024年2月26日(上月的周一),但3月的首个周一应该是3月4日。
问题出在:当当月第一天晚于周一(周二到周日)时,你的SQL会往回追溯周一,而不是在当月范围内往后找第一个周一。
更优的实现方式
根据你的星期配置(周日=0,周一=1),推荐两种直观的正确写法:
写法1:分步计算(可读性高)
先拿到当月第一天,再根据星期数判断调整:
DECLARE @targetDate DATE = '2024-03-15'; DECLARE @firstDayOfMonth DATE = DATEFROMPARTS(YEAR(@targetDate), MONTH(@targetDate), 1); -- 更直观的月初获取方式 SELECT CASE WHEN DATEPART(WEEKDAY, @firstDayOfMonth) = 1 THEN @firstDayOfMonth ELSE DATEADD(DAY, 8 - DATEPART(WEEKDAY, @firstDayOfMonth), @firstDayOfMonth) END AS FirstMondayOfMonth;
逻辑解释:
- 若当月第一天就是周一(
WEEKDAY=1),直接返回; - 若是其他日期,比如周五(
WEEKDAY=5),8-5=3,加3天就得到当月第一个周一。
写法2:单语句简化版
如果不想用变量,也可以把逻辑合并成一条:
SELECT DATEADD(DAY, CASE DATEPART(WEEKDAY, DATEFROMPARTS(YEAR([DATE]), MONTH([DATE]), 1)) WHEN 1 THEN 0 ELSE 8 - DATEPART(WEEKDAY, DATEFROMPARTS(YEAR([DATE]), MONTH([DATE]), 1)) END, DATEFROMPARTS(YEAR([DATE]), MONTH([DATE]), 1) ) AS FirstMondayOfMonth;
关于“没有月初函数”的疑问
SQL Server确实没有内置的FIRSTDAYOFMONTH函数,但有两种简洁的替代方式:
- 用
DATEFROMPARTS(YEAR(@date), MONTH(@date), 1)(SQL Server 2012+支持),语法最直观; - 就是你用的
DATEADD(DAY, 1, EOMONTH(DATEADD(MONTH, -1, @date))),兼容性更好。
内容的提问来源于stack exchange,提问作者J. Mini
相关产品推荐
相关产品推荐

