業務開發中頻繁需要按自然時間窗口統計數據 (如「本月迄今」、「上月同期」)。本文整理 MySQL 通用的日期邊界計算技巧,所有語句基於 CURDATE() (當前日期),可直接用於 WHERE 子句或報表查詢。
| 需求 | SQL 語句 | 原理解析 |
|---|---|---|
| 本月第一天 (00:00:00) | SELECT DATE_SUB(CURDATE(), INTERVAL DAY(CURDATE())-1 DAY); |
當前日期減去 (當前日-1) 天,即回到 1 號 |
| 本月最後一天 (23:59:59 需自行拼接時間) | SELECT LAST_DAY(CURDATE()); |
內建函數直接返回當月最後一天日期 |
| 上月第一天 | SELECT DATE_SUB(DATE_SUB(CURDATE(), INTERVAL DAY(CURDATE())-1 DAY), INTERVAL 1 MONTH); |
先算本月 1 號,再減 1 個月 |
| 本周第一天 (週一為週首,MySQL 標準) | SELECT DATE_ADD(CURDATE(), INTERVAL -WEEKDAY(CURDATE()) DAY); |
WEEKDAY() 返回 0(週一)~6(週七),負向加回週一 |
| 本周最後一天 (週日) | SELECT DATE_ADD(CURDATE(), INTERVAL (6-WEEKDAY(CURDATE())) DAY); |
週一為 0,週日為 6,差值即為需加天數 |
| 上周第一天 (週一) | SELECT DATE_SUB(DATE_ADD(CURDATE(), INTERVAL -WEEKDAY(CURDATE()) DAY), INTERVAL 1 WEEK); |
本周一減 7 天 |
| 季度第一天 | SELECT DATE_SUB(CURDATE(), INTERVAL (MONTH(CURDATE())-1)%3 MONTH);再配合 DAY(...)-1 回到 1 號 |
利用取模推算季度起始月 |
-- 查詢本月訂單
SELECT * FROM orders
WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL DAY(CURDATE())-1 DAY)
AND create_time < DATE_ADD(LAST_DAY(CURDATE()), INTERVAL 1 DAY);
-- 查詢上周完整數據 (週一至週日)
SELECT * FROM logs
WHERE log_date BETWEEN
DATE_SUB(DATE_ADD(CURDATE(), INTERVAL -WEEKDAY(CURDATE()) DAY), INTERVAL 1 WEEK)
AND DATE_SUB(DATE_ADD(CURDATE(), INTERVAL -WEEKDAY(CURDATE()) DAY), INTERVAL 1 DAY);
CURDATE() 返回 DATE 類型 (無時間);若欄位為 DATETIME/TIMESTAMP,上界需加 1 天或使用 < 下一個邊界 避免漏掉當天 23:59:59 的數據。DATE_TRUNC() (實驗性) 或 CTE 簡化複雜邊界計算。待續……更多場景 (如「最近 N 個自然月」、「同比環比基準日」) 將在後續補充。