BETWEEN AND是闭区间,左右边界均包含;但DATETIME/TIMESTAMP类型下'2024-01-31'隐式转为'2024-01-31 00:00:00',会遗漏当日后续时间,应显式写'2024-01-31 23:59:59'或用< '2024-02-01'。

WHERE子句里用BETWEEN AND写日期范围时,边界值是否包含?
BETWEEN AND是闭区间,左右边界都包含。比如 date_column BETWEEN '2024-01-01' AND '2024-01-31' 会匹配到 '2024-01-01 00:00:00' 和 '2024-01-31 00:00:00',但不会匹配 '2024-01-31 14:22:05'(除非字段类型是 DATE 且无时间部分)。
常见错误是以为它自动覆盖整天,结果漏掉当天下午的数据:
- 字段是
DATETIME或TIMESTAMP类型时,'2024-01-31'会被隐式转成'2024-01-31 00:00:00',导致 1 月 31 日 00:01 之后的数据全被排除 - 正确做法是显式写终点为
'2024-01-31 23:59:59',或更稳妥地用+ <code> 组合
MySQL和PostgreSQL对字符串日期的隐式转换行为不同
写 BETWEEN '2024-01-01' AND '2024-01-31' 看似简洁,但实际执行依赖数据库如何解析字符串。MySQL 通常能宽松转换,PostgreSQL 则更严格,可能报错 ERROR: invalid input syntax for type date。
建议统一显式转换:
- MySQL:用
STR_TO_DATE('2024-01-01', '%Y-%m-%d')或直接传DATE字面量(如DATE '2024-01-01',MySQL 8.0+ 支持) - PostgreSQL:必须用
DATE '2024-01-01'或'2024-01-01'::DATE - SQL Server:推荐
CONVERT(DATE, '2024-01-01'),避免受语言/区域设置影响
用BETWEEN AND查“最近7天”容易出错的三个点
动态日期范围是高频需求,但直接套 BETWEEN DATE_SUB(CURDATE(), INTERVAL 6 DAY) AND CURDATE() 有隐患:
- 如果字段含时间(如
DATETIME),CURDATE()返回的是'2024-04-05'(即'2024-04-05 00:00:00'),终点只覆盖到当天零点,丢掉所有非零点数据 -
DATE_SUB(CURDATE(), INTERVAL 6 DAY)算出来是 3 月 30 日,但“最近 7 天”应是 3 月 30 日 00:00 到 4 月 5 日 23:59:59 —— 这里天数计算逻辑易混淆 - 跨月时(如从 4 月 1 日倒推 6 天),某些旧版 MySQL 在
DATE_SUB中处理月末边界不一致,建议用ADDDATE(CURDATE(), INTERVAL -6 DAY)替代
比BETWEEN AND更安全的日期范围写法
多数场景下,显式用两个比较符反而更可控、可读性更强,也规避了 BETWEEN 对时间精度的模糊性:
WHERE date_column >= '2024-01-01' AND date_column < '2024-02-01'
这种写法的好处:
- 右边界用
而不是 <code>,天然覆盖整个月(只要 <code>'2024-02-01'是精确到日的起点) - 索引友好:大多数数据库对
>=+组合能有效走范围索引,而 <code>BETWEEN在某些执行计划里可能被重写为等价形式,但不保证 - 时区安全:若字段是
TIMESTAMP,且应用层与数据库时区不一致,显式写法更容易对齐预期时间点
真正要注意的从来不是语法能不能写,而是字段类型、存储精度、时区设置这三项——它们共同决定一行记录到底算不算“在范围内”。

















