計算指定月份包含多少個星期日(或任意週幾),是報表、排程、薪資試算常見需求。本文提供通用集合思維解法:以數字序列表(Tally Table)產生該月所有日期,再套用日期函數篩選目標週幾並計數。並針對 MySQL、SQL Server、PostgreSQL、Oracle 提供對應語法。
'2006-09-01')。WEEKDAY()/DAYOFWEEK()/DATEPART(WEEKDAY, ...) 判斷是否為星期日,SUM(CASE...) 計數。CREATE TABLE dbo.Integers (i INT NOT NULL PRIMARY KEY);
INSERT INTO dbo.Integers (i) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
-- 如需更大範圍,可跨表 Cartesian Product 擴展至百萬級
SET @day1 = '2006-09-01';
SELECT COUNT(*) AS sundays
FROM (
SELECT DATE_ADD(@day1, INTERVAL (10*tens.i + units.i) DAY) AS adate
FROM Integers AS tens
CROSS JOIN Integers AS units
WHERE DATE_ADD(@day1, INTERVAL (10*tens.i + units.i) DAY) < DATE_ADD(@day1, INTERVAL 1 MONTH)
) d
WHERE DAYOFWEEK(adate) = 1; -- 1 = Sunday
DECLARE @day1 DATE = '20060901';
SELECT COUNT(*) AS sundays
FROM (
SELECT DATEADD(DAY, 10*tens.i + units.i, @day1) AS adate
FROM Integers AS tens
CROSS JOIN Integers AS units
WHERE DATEADD(DAY, 10*tens.i + units.i, @day1) < DATEADD(MONTH, 1, @day1)
) d
WHERE DATEPART(WEEKDAY, adate) = 1; -- 預設 1=Sunday,受 SET DATEFIRST 影響
-- 更安全寫法:WHERE (DATEPART(WEEKDAY, adate) + @@DATEFIRST - 1) % 7 + 1 = 7
SELECT COUNT(*) AS sundays
FROM generate_series(
DATE '2006-09-01',
DATE '2006-09-01' + INTERVAL '1 month' - INTERVAL '1 day',
INTERVAL '1 day'
) AS adate
WHERE EXTRACT(ISODOW FROM adate) = 7; -- ISODOW: 1=Mon ... 7=Sun
SELECT COUNT(*) AS sundays
FROM (
SELECT TRUNC(TO_DATE('2006-09-01', 'YYYY-MM-DD')) + LEVEL - 1 AS adate
FROM dual
CONNECT BY LEVEL <= (LAST_DAY(TO_DATE('2006-09-01', 'YYYY-MM-DD')) - TRUNC(TO_DATE('2006-09-01', 'YYYY-MM-DD')) + 1)
)
WHERE TO_CHAR(adate, 'DY', 'NLS_DATE_LANGUAGE=AMERICAN') = 'SUN';
現代資料庫多支援直接計算:
DATEDIFF(DAY, @firstDay, @lastDay) / 7 + CASE WHEN DATEPART(WEEKDAY, @firstDay) <= 1 AND 1 <= DATEPART(WEEKDAY, @lastDay) THEN 1 ELSE 0 END(需處理跨週邊界)。EXTRACT(DAY FROM (DATE_TRUNC('MONTH', d) + INTERVAL '1 MONTH - 1 DAY') - DATE_TRUNC('MONTH', d)) / 7 + ...建議:數字序列表法通用性最強、邏輯清晰、易除錯,適合大多數場景;極高頻呼叫時可考慮內建函數優化。
WEEK(adate)、DAY(adate) 即可輸出前端渲染所需結構。1(Sunday)替換為 2-7(Monday-Saturday)。