【SQL】计算一年内每个月份的周数据
通过SQL编程实现以下功能:计算2025年内每个月份的周数据。要求每周从周日开始作为第一天,按月进行自然周分组,最终输出包含月份和周次的结果集。
SET DATEFIRST 7; -- 设置周日作为一周的第一天DECLARE @FirstDayOfYEAR DATE = '2025-01-01'; -- 年份起始日-- 生成全年所有月份
WITH Months AS (SELECT MonthNumber = 1,FirstDayOfMonth = @FirstDayOfYEAR,EndOfMonth = DATEADD(DAY, -1, DATEADD(MONTH, 1, @FirstDayOfYEAR))UNION ALLSELECT MonthNumber + 1,DATEADD(MONTH, 1, FirstDayOfMonth),DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEADD(MONTH, 1, FirstDayOfMonth)))FROM MonthsWHERE MonthNumber < 12
),
-- 每个月的第一个周日
FirstSundayCTE AS (SELECT *,FirstSunday = CASE WHEN DATEPART(WEEKDAY, FirstDayOfMonth) = 1 THEN FirstDayOfMonthELSE DATEADD(DAY, (8 - DATEPART(WEEKDAY, FirstDayOfMonth)) % 7, FirstDayOfMonth)ENDFROM Months
),
-- 递归生成每周区间
Weeks AS (-- 第一周(可能跨月)SELECT MonthNumber,WeekNumber = 1,StartDate = FirstDayOfMonth,EndDate = CASE WHEN FirstSunday > FirstDayOfMonth THEN DATEADD(DAY, -1, FirstSunday) -- 非完整周ELSE DATEADD(DAY, 6, FirstDayOfMonth) -- 完整周(周日为第一天)END,EndOfMonthFROM FirstSundayCTEWHERE FirstSunday >= FirstDayOfMonth -- 允许首日为周日UNION ALL-- 后续周(周日到下周六)SELECT MonthNumber,WeekNumber = WeekNumber + 1,StartDate = DATEADD(DAY, 1, Prev.EndDate),EndDate = CASE WHEN DATEADD(DAY, 6, DATEADD(DAY, 1, Prev.EndDate)) > EndOfMonth THEN EndOfMonth ELSE DATEADD(DAY, 6, DATEADD(DAY, 1, Prev.EndDate)) END,EndOfMonthFROM Weeks AS PrevWHERE DATEADD(DAY, 1, Prev.EndDate) <= EndOfMonth
)SELECT MonthNumber, WeekNumber, StartDate, EndDate FROM Weeks;