這個 SQL Script 是針對 Jack 的飯店業 BI 需要看到周變化,所以整理出來的 Script BI 一般是看趨勢,理論上不會看到這麼細,但是要做當然是可以的 /* 以年度共幾周為單位取日期區間(一年共 52 周) 以下內容是 ChatGPT 的結果,令人驚豔 Michael 20250604 */ SET DATEFIRST 7; -- 設定週日為每週第一天 WITH Weeks AS ( SELECT DATEADD(DAY, -(DATEPART(WEEKDAY, DATEFROMPARTS(2025, 1, 1)) - 1), DATEFROMPARTS(2025, 1, 1)) AS WeekStart UNION ALL SELECT DATEADD(WEEK, 1, WeekStart) FROM Weeks WHERE DATEADD(WEEK, 1, WeekStart) <= DATEFROMPARTS(2025, 12, 31) ), WeeksWithMonth AS ( SELECT ROW_NUMBER() OVER (ORDER BY WeekStart) AS WeekNumber, WeekStart, DATEADD(DAY, 6, WeekStart) AS EndDate, MONTH(WeekStart) AS MonthNumber, DATENAME(MONTH, WeekStart) AS MonthName, YEAR(WeekStart) AS YearNumber FROM Weeks WHERE YEAR(WeekStart) = 2025 OR YEAR(DATEADD(DAY, 6, WeekStart)) = 2025 ), WeeksWithMonthRank AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY YearNumber, MonthNumber ORDER BY WeekStart) AS WeekOfMonth FROM WeeksWithMonth ) SELECT WeekNumber, WeekStart AS StartDate, EndDate, MonthName, MonthNumber, WeekOfMonth -- ?? 當月第幾週 -- into Year_WeekData FROM WeeksWithMonthRank ORDER BY StartDate OPTION (MAXRECURSION 100) /* 以下的寫法會將跨月的周,拆成 2 筆 目的是如果要以月為單位看第幾周,就用下面的語法 */ -- SET DATEFIRST 7; -- 設定週日為一週的第一天(星期日) SET DATEFIRST 1; -- 設定週一為一週的第一天(星期一) -- 產生所有週的開始日 WITH Weeks AS ( SELECT DATEADD(DAY, -(DATEPART(WEEKDAY, DATEFROMPARTS(2025, 1, 1)) - 1), DATEFROMPARTS(2025, 1, 1)) AS WeekStart UNION ALL SELECT DATEADD(WEEK, 1, WeekStart) FROM Weeks WHERE DATEADD(WEEK, 1, WeekStart) <= DATEFROMPARTS(2025, 12, 31) ), -- 加上 WeekNumber(全年第幾週) WeeksWithNumber AS ( SELECT ROW_NUMBER() OVER (ORDER BY WeekStart) AS WeekNumber, WeekStart, DATEADD(DAY, 6, WeekStart) AS WeekEnd FROM Weeks ), -- 將每週展開成7天 DaysInWeek AS ( SELECT W.WeekNumber, W.WeekStart, DATEADD(DAY, N.number, W.WeekStart) AS DayDate FROM WeeksWithNumber W JOIN master.dbo.spt_values N ON N.type = 'P' AND N.number BETWEEN 0 AND 6 WHERE YEAR(DATEADD(DAY, N.number, W.WeekStart)) = 2025 ), -- 拆分週中涉及的每個月份的起訖日 WeekMonthSplit AS ( SELECT WeekNumber, WeekStart, MONTH(DayDate) AS MonthNumber, DATENAME(MONTH, DayDate) AS MonthName, YEAR(DayDate) AS YearNumber, MIN(DayDate) AS StartDate, MAX(DayDate) AS EndDate FROM DaysInWeek GROUP BY WeekNumber, WeekStart, MONTH(DayDate), DATENAME(MONTH, DayDate), YEAR(DayDate) ), -- 加上「當月第幾週」 FinalResult AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY YearNumber, MonthNumber ORDER BY StartDate) AS WeekOfMonth FROM WeekMonthSplit ) -- 輸出最終結果 SELECT ROW_NUMBER() OVER (ORDER BY StartDate) AS RecordID, WeekNumber, WeekStart, StartDate, EndDate, MonthName, MonthNumber, WeekOfMonth -- into Year_WeekData FROM FinalResult ORDER BY StartDate OPTION (MAXRECURSION 100)