本文系統整理 MySQL 中按天、週、月維度查詢數據的各種 SQL 寫法,涵蓋當天、當月第一天、上月第一天、本週第一天、上週範圍、時間戳雙向轉換等高頻場景。
CREATE TABLE IF NOT EXISTS t (
id INT,
addTime DATETIME DEFAULT '0000-00-00 00:00:00'
);
INSERT INTO t VALUES (1, '2012-07-12 21:00:00');
INSERT INTO t VALUES (2, '2012-07-22 21:00:00');
| # | 寫法 | 說明 | 推薦度 |
|---|---|---|---|
| 1 | WHERE DATE_FORMAT(addTime,'%Y-%m-%d') = DATE_FORMAT(NOW(),'%Y-%m-%d') | 格式化比較,通用但無法用索引 | ⭐ |
| 2 | WHERE addTime >= DATE_FORMAT(NOW(),'%Y-%m-%d') | 範圍查詢,可用索引 | ⭐⭐⭐ |
| 3 | WHERE DATEDIFF(addTime, NOW()) = 0 | 日期差為 0,語義清晰,可用索引 (5.6+) | ⭐⭐⭐⭐ |
| 4 | WHERE addTime BETWEEN UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 1 DAY)) AND UNIX_TIMESTAMP(NOW()) | 時間戳範圍,適用 INT 時間戳欄位 | ⭐⭐ |
日期函數差異: NOW() 含時分秒,CURDATE()/CURRENT_DATE() 僅日期。
-- 1. 今天是當月第幾天
SELECT DAYOFMONTH(NOW());
-- 2. 當月第一天 (00:00:00)
SELECT DATE_SUB(NOW(), INTERVAL DAYOFMONTH(NOW()) - 1 DAY);
-- 或
SELECT DATE_FORMAT(NOW(), '%Y-%m-01');
-- 3. 上月第一天
SELECT DATE_SUB(
DATE_SUB(NOW(), INTERVAL DAYOFMONTH(NOW()) - 1 DAY),
INTERVAL 1 MONTH
);
日期運算核心函數:
DATE_ADD(date, INTERVAL expr unit):增加間隔DATE_SUB(date, INTERVAL expr unit):減少間隔INTERVAL expr unit:expr 可為負值表示反向-- 1. 今天是週幾 (0=週一, 6=週日)
SELECT WEEKDAY(NOW());
-- 2. 本週第一天 (週一 00:00:00)
SELECT DATE_SUB(NOW(), INTERVAL WEEKDAY(NOW()) DAY);
-- 或
SELECT DATE_ADD(NOW(), INTERVAL -WEEKDAY(NOW()) DAY);
-- 或 (僅日期)
SELECT CURDATE() - INTERVAL WEEKDAY(CURDATE()) DAY;
-- 3. 上週第一天到現在的數據
SELECT * FROM t
WHERE addTime >= DATE_FORMAT(
DATE_SUB(DATE_SUB(NOW(), INTERVAL WEEKDAY(NOW()) DAY), INTERVAL 1 WEEK),
'%Y-%m-%d'
);
-- 1. 時間戳 → 日期時間
SELECT FROM_UNIXTIME(1336542121);
-- 結果: 2012-05-09 14:22:01
-- 2. 日期時間 → 時間戳
SELECT UNIX_TIMESTAMP('2013-04-08');
-- 結果: 1365350400
-- 3. 帶時區轉換
SELECT FROM_UNIXTIME(1336542121, '%Y-%m-%d %H:%i:%s');
SELECT UNIX_TIMESTAMP('2013-04-08 12:00:00');
-- 當天
WHERE addTime BETWEEN UNIX_TIMESTAMP(CURDATE()) AND UNIX_TIMESTAMP(CURDATE() + INTERVAL 1 DAY)
-- 當月
WHERE addTime BETWEEN UNIX_TIMESTAMP(DATE_FORMAT(NOW(), '%Y-%m-01'))
AND UNIX_TIMESTAMP(DATE_FORMAT(DATE_ADD(NOW(), INTERVAL 1 MONTH), '%Y-%m-01'))
-- 當週
WHERE addTime BETWEEN UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL WEEKDAY(NOW()) DAY))
AND UNIX_TIMESTAMP(DATE_ADD(DATE_SUB(NOW(), INTERVAL WEEKDAY(NOW()) DAY), INTERVAL 1 WEEK))
-- 直接日期運算
WHERE addTime >= CURDATE() - INTERVAL 1 DAY
WHERE addTime >= CURDATE() - INTERVAL 1 WEEK
WHERE addTime >= CURDATE() - INTERVAL 1 MONTH
BETWEEN 包含兩端,日期範圍查詢建議 [start, end) 半開區間DATE()/STR_TO_DATE()AND addTime IS NOT NULL