between用于时间范围查询时默认截到日级零点,不带时间部分会漏数据;如where create_time between '2024-01-01' and '2024-01-31'实际等价于create_time >= '2024-01-01 00:00:00' and create_time

BETWEEN 用于时间范围查询时,默认只截到日级零点,不带时间部分的写法几乎必然漏数据。
DATETIME/TIMESTAMP 字段用 BETWEEN '2024-01-01' AND '2024-01-31' 会丢一整天
MySQL 遇到字符串形式的日期(如 '2024-01-01')会隐式补全为 '2024-01-01 00:00:00',所以该语句实际查的是从零点到零点的区间,'2024-01-31 14:22:05' 这类记录直接被过滤掉。
- 错误示例:
WHERE create_time BETWEEN '2024-01-01' AND '2024-01-31'→ 实际等价于create_time >= '2024-01-01 00:00:00' AND create_time - 正确做法:显式写出完整时间边界,或改用左闭右开写法
- 推荐替代:
WHERE create_time >= '2024-01-01' AND create_time —— 更清晰、可索引、无微秒截断风险
DATE 类型字段可以安全用 BETWEEN,但仍有风格一致性问题
DATE 字段本身不含时间部分,BETWEEN '2024-01-01' AND '2024-01-31' 是语义正确的,不会隐式补零导致逻辑偏差。
- 但若后续字段类型被改成
DATETIME,同一语句立刻失效,维护成本高 - 团队协作中混合使用
BETWEEN和>= + 容易引发理解分歧 - 统一用
>= + 写法,能自然兼容所有时间精度(秒、微秒),且利于 MySQL 的 range index 下推
复合条件中 NOT BETWEEN 和 OR 优先级容易翻车
NOT BETWEEN 本身是原子操作,但一旦混入 OR,不加括号就会因运算符优先级出错。
- 危险写法:
WHERE status = 'active' OR updated_at BETWEEN '2024-01-01' AND '2024-01-31'→ 实际执行为(status = 'active' OR updated_at BETWEEN ...),可能返回大量非预期记录 - 必须加括号:
WHERE status = 'active' AND (updated_at BETWEEN '2024-01-01' AND '2024-01-31') - 更稳妥:
WHERE status = 'active' AND updated_at >= '2024-01-01' AND updated_at ,括号天然清晰
NULL 值和字段类型不匹配是静默陷阱
BETWEEN 对 NULL 返回 UNKNOWN,整行被过滤;字段类型与字面量类型不一致会触发隐式转换,可能绕过索引或产生精度误差。
-
updated_at为NULL时,NULL BETWEEN '2024-01-01' AND '2024-01-31'永远不成立,不会出现在结果里 - 如果参数传的是字符串
'2024-01-01'而字段是DATETIME,MySQL 仍能转换,但若字段加了函数(如DATE(updated_at)),索引就彻底失效 - 数值字段如
DECIMAL(10,2),别用'100',要用100.00;浮点型字段慎用BETWEEN,二进制表示误差可能导致边界值意外丢失
真正难的不是写对一行 SQL,而是让同一套查询逻辑在 DATE/DATETIME/TIMESTAMP 字段上行为一致,且不依赖 MySQL 的隐式补零或类型转换。左闭右开(>= + )不是“更啰嗦”,而是把时间边界的含义显式钉死在代码里——这点在跨时区、微秒精度、联合索引优化时尤为关键。











