在 SQL Server 開發中,針對日期時間欄位進行「當天」或「當月」篩選是極高頻的需求。但資料庫儲存的 datetime 型別包含時分秒毫秒(如 2007-02-02 16:50:08.050),直接與 GETDATE() 比較永遠無法命中資料。本文將系統梳理三種主流解法,並對比效能優劣,助你寫出既正確又高效的查詢。
資料表欄位 TimeField 為 datetime,精確到毫秒;GETDATE() 回傳當下完整時間。若寫 WHERE TimeField = GETDATE(),除非資料恰好在同一毫秒寫入,否則永無結果。解決思路只有一個:**將雙方統一到同一精度(日期或月份)再比較**。
-- 當天記錄
SELECT * FROM VIEW_CountBill
WHERE CONVERT(varchar(10), [time], 120) = CONVERT(varchar(10), GETDATE(), 120);
-- 當月記錄(同理)
SELECT * FROM VIEW_CountBill
WHERE CONVERT(varchar(7), [time], 120) = CONVERT(varchar(7), GETDATE(), 120);
style 120 輸出 yyyy-mm-dd hh:mi:ss,varchar(10) 截取前 10 碼即 yyyy-mm-dd。-- 當天:計算「今天 00:00:00」與「明天 00:00:00」區間
DECLARE @todayStart datetime = DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0);
DECLARE @tomorrowStart datetime = DATEADD(day, 1, @todayStart);
SELECT * FROM VIEW_CountBill
WHERE [time] >= @todayStart AND [time] < @tomorrowStart;
-- 當月:同理計算月初、下月初
DECLARE @monthStart datetime = DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0);
DECLARE @nextMonthStart datetime = DATEADD(month, 1, @monthStart);
SELECT * FROM VIEW_CountBill
WHERE [time] >= @monthStart AND [time] < @nextMonthStart;
-- 當天
SELECT * FROM VIEW_CountBill
WHERE DATETRUNC(day, [time]) = DATETRUNC(day, GETDATE());
-- 當月
SELECT * FROM VIEW_CountBill
WHERE DATETRUNC(month, [time]) = DATETRUNC(month, GETDATE());
DATETRUNC 仍屬欄位運算,**無法用索引**,僅適合中小表或臨時查詢。| 方案 | 語法複雜度 | 能否用索引 | 推薦場景 |
|---|---|---|---|
| CONVERT 字串 | 低 | ❌ | 舊版本相容、小表、臨時查詢 |
| DATEADD/DATEDIFF 區間 | 中 | ✅ | **生產環境大表首選** |
| DATETRUNC | 極低 | ❌ | SQL 2016+、開發自查、中小表 |
INSERT INTO student(studentid, time1) VALUES ('15', GETDATE());INSERT INTO tablename (fieldname) VALUES (NOW());WHERE MONTH([time]) = MONTH(GETDATE()) 會跨年錯誤(1 月會匹配去年 1 月),且同樣導致索引失效。BETWEEN '2024-01-01' AND '2024-01-31 23:59:59.997' 因精度問題可能遺漏或多算資料,**永遠改用半開區間 >= 且 <**。DATETRUNC 簡化開發期查詢,上線前改寫為區間形式。