核心函數回顧
| 函數 | 用途 | 語法 |
DATEDIFF | 計算兩日期間的間隔數(年/月/週/日/時/分/秒/毫秒) | DATEDIFF(interval, startdate, enddate) |
DATEADD | 在指定日期加減間隔,回傳新日期 | DATEADD(interval, number, date) |
關鍵技巧:以「基準日」0(即 1900-01-01 00:00:00.000)為錨點,計算目標日期與基準日的間隔數,再加回基準日,即可截取所需週期邊界。
常用週期邊界計算範本
| 需求 | T-SQL | 說明 |
| 本月第一天 00:00 | DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0) | 月間隔數加回基準日 |
| 本週一 00:00 | DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()), 0) | 預設週一為週首(受 SET DATEFIRST 影響) |
| 今年第一天 00:00 | DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0) | |
| 本季第一天 00:00 | DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0) | |
| 今天 00:00 (午夜) | DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0) | 截掉時間部分 |
| 上個月最後一天 23:59:59.997 | DATEADD(MS, -3, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) | 本月第一天減 3 毫秒 |
| 去年最後一天 23:59:59.997 | DATEADD(MS, -3, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0)) | |
| 本月最後一天 23:59:59.997 | DATEADD(MS, -3, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) + 1, 0)) | 下月第一天減 3 毫秒 |
| 今年最後一天 23:59:59.997 | DATEADD(MS, -3, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()) + 1, 0)) | |
| 本月第一個週一 | DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEADD(DAY, 6 - DATEPART(DAY, GETDATE()), GETDATE())), 0) | 先算本月 6 號,再取該週週一 |
間隔代碼速查
| 間隔 | 代碼 (縮寫) |
| 年 | year, yy, yyyy |
| 季 | quarter, qq, q |
| 月 | month, mm, m |
| 週 | week, wk, ww |
| 日 | day, dd, d |
| 時 | hour, hh |
| 分 | minute, mi, n |
| 秒 | second, ss, s |
| 毫秒 | millisecond, ms |
實務應用範例
1. 當月營收統計篩選
DECLARE @StartOfMonth DATETIME = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0);
DECLARE @StartOfNextMonth DATETIME = DATEADD(MONTH, 1, @StartOfMonth);
SELECT SUM(Amount) AS MonthlyRevenue
FROM Sales
WHERE OrderDate >= @StartOfMonth
AND OrderDate < @StartOfNextMonth; -- 半開區間,避免最後一天時間部分遺漏
2. 近 30 天滾動視窗
WHERE EventDate >= DATEADD(DAY, -30, CAST(GETDATE() AS DATE))
AND EventDate < CAST(GETDATE() AS DATE);
3. 依週分組統計(週一為週首)
SELECT
DATEADD(WEEK, DATEDIFF(WEEK, 0, OrderDate), 0) AS WeekStart,
COUNT(*) AS OrderCount
FROM Orders
GROUP BY DATEADD(WEEK, DATEDIFF(WEEK, 0, OrderDate), 0)
ORDER BY WeekStart;
注意事項
SET DATEFIRST 影響 WEEK 間隔的週首定義(1=週一, 7=週日,預設 7)。跨環境部署建議明確設定或改用 DATEPART(WEEKDAY, ...) 邏輯。
DATETIME 精度 3.33 ms,故「一天結束」用 23:59:59.997;DATETIME2/DATE 建議改用半開區間 < NextPeriodStart。
- 避免在
WHERE 子句對欄位使用函數(如 WHERE DATEADD(...)=...),導致索引失效;改用常數邊界比較。
現代替代方案(SQL Server 2022+ / Azure SQL)
-- DATETRUNC (2022+) 直接截斷到指定精度
SELECT DATETRUNC(MONTH, GETDATE()) AS MonthStart;
SELECT DATETRUNC(WEEK, GETDATE()) AS WeekStart;