SQL Server中如何判断指定日期的日是否在两个日期的日区间内(含月末场景)
SQL Server 检查bookdate周年日是否在日期范围内的正确方法
你的原查询只比较日期的日部分,当startdate和enddate跨月时(比如2月28日到3月1日),日的范围是28到1,此时bookdate的日(28)不在这个区间内,会错误返回No,但实际上2月28日属于[2-28, 3-1]范围,应该返回Yes。
下面提供两种可靠的解决方案:
方案1:基于基准年的月日区间比较
把所有日期转换到同一个闰年(比如2000年,避免2月29日的处理问题)的月日组合,再判断bookdate的月日是否落在startdate和enddate的月日区间内,同时支持跨年度的情况(比如12月到次年1月)。
DECLARE @bookdate DATE = '2-28-2023' ,@startdate DATE = '2-28-2023' ,@enddate DATE = '3-1-2023'; -- 转换为2000年(闰年)的月日日期,统一基准 DECLARE @book_benchmark DATE = DATEFROMPARTS(2000, MONTH(@bookdate), DAY(@bookdate)); DECLARE @start_benchmark DATE = DATEFROMPARTS(2000, MONTH(@startdate), DAY(@startdate)); DECLARE @end_benchmark DATE = DATEFROMPARTS(2000, MONTH(@enddate), DAY(@enddate)); SELECT CASE -- 区间未跨年,直接判断月日是否在范围内 WHEN @start_benchmark <= @end_benchmark AND @book_benchmark BETWEEN @start_benchmark AND @end_benchmark THEN 'Yes' -- 区间跨年(如12月到次年1月),判断月日是否落在区间两端 WHEN @start_benchmark > @end_benchmark AND (@book_benchmark >= @start_benchmark OR @book_benchmark <= @end_benchmark) THEN 'Yes' ELSE 'No' END AS isAnniversary;
方案2:生成实际周年日并检查范围
直接生成bookdate在startdate和enddate覆盖年份内的周年日期,判断该日期是否存在于目标区间,同时自动处理闰年2月29日的特殊情况(非闰年时调整为2月28日)。
DECLARE @bookdate DATE = '2-28-2023' ,@startdate DATE = '2-28-2023' ,@enddate DATE = '3-1-2023'; SELECT CASE WHEN EXISTS ( SELECT 1 -- 生成对应年份的周年日,处理闰年2月29的情况 WHERE COALESCE( TRY_CAST(DATEFROMPARTS(y, MONTH(@bookdate), DAY(@bookdate)) AS DATE), DATEFROMPARTS(y, MONTH(@bookdate), 28) -- 非闰年时2月29日替换为2月28日 ) BETWEEN @startdate AND @enddate -- 遍历区间覆盖的年份(最多2年,所以取当前年和下一年) FROM (VALUES (YEAR(@startdate)), (YEAR(@startdate)+1)) AS years(y) ) THEN 'Yes' ELSE 'No' END AS isAnniversary;
两种方案的区别
- 方案1更简洁,适合只需要判断月日是否在区间内,不纠结实际周年日期是否存在的场景。
- 方案2更精准,直接验证真实存在的周年日期是否在目标区间,完全贴合业务逻辑。
内容的提问来源于stack exchange,提问作者Ced
相关产品推荐
相关产品推荐

