首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 日期篩選:高效查詢當天與當月記錄的實戰技巧

     編輯:關於SqlServer

前言

在 SQL Server 開發中,針對日期時間欄位進行「當天」或「當月」篩選是極高頻的需求。但資料庫儲存的 datetime 型別包含時分秒毫秒(如 2007-02-02 16:50:08.050),直接與 GETDATE() 比較永遠無法命中資料。本文將系統梳理三種主流解法,並對比效能優劣,助你寫出既正確又高效的查詢。

核心難點:時間精度不匹配

資料表欄位 TimeField 為 datetime,精確到毫秒;GETDATE() 回傳當下完整時間。若寫 WHERE TimeField = GETDATE(),除非資料恰好在同一毫秒寫入,否則永無結果。解決思路只有一個:**將雙方統一到同一精度(日期或月份)再比較**。

方案一:CONVERT 截取日期字串(相容性最好,但無法用索引)

-- 當天記錄
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。
  • 缺點:欄位經函數運算導致 **SARGable 失效**,無法利用索引,大表全掃描效能極差。

方案二:DATEADD/DATEDIFF 日期運算(推薦,可用索引)

-- 當天:計算「今天 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;
  • 優點:查詢條件為「欄位 >= 常數 AND 欄位 < 常數」,**完美支援索引 Seek**,大表毫秒級返回。
  • 適用版本:SQL Server 2008+ 皆可。

方案三:SQL Server 2016+ 新函數 DATETRUNC(最簡潔)

-- 當天
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+、開發自查、中小表

進階補充:JSP/MySQL 插入當前時間

  • SQL Server:INSERT INTO student(studentid, time1) VALUES ('15', GETDATE());
  • MySQL:INSERT INTO tablename (fieldname) VALUES (NOW());

常見誤區提醒

  1. 用 MONTH() / YEAR() 單獨比較月份:WHERE MONTH([time]) = MONTH(GETDATE()) 會跨年錯誤(1 月會匹配去年 1 月),且同樣導致索引失效。
  2. BETWEEN 陷阱:BETWEEN '2024-01-01' AND '2024-01-31 23:59:59.997' 因精度問題可能遺漏或多算資料,**永遠改用半開區間 >= 且 <**。

最佳實踐建議

  1. **大表務必建立日期欄位索引**。
  2. **統一使用「半開區間 + 日期運算」寫法**,既標準又高效。
  3. 若專案鎖定 SQL Server 2016+,可考慮 DATETRUNC 簡化開發期查詢,上線前改寫為區間形式。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved