131 lines
3.2 KiB
Plaintext
131 lines
3.2 KiB
Plaintext
這個 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)
|