BETWEEN查询日期字段易漏数据,因字符串日期被隐式转为00:00:00导致右边界截断;应改用左闭右开区间(>= '2024-01-01' AND < '2024-02-01')或显式转换类型。

直接用 BETWEEN 查询日期字段可能漏数据
很多人写 WHERE date_col BETWEEN '2024-01-01' AND '2024-01-31',以为能查出整月数据,结果发现 2024-01-31 23:59:59 的记录没出来。根本原因是 BETWEEN 是闭区间,但字符串字面量 `'2024-01-31'` 在多数数据库里会被隐式转成 '2024-01-31 00:00:00',所以实际查的是 ['2024-01-01 00:00:00', '2024-01-31 00:00:00'],末尾一整天都丢了。
- MySQL / PostgreSQL / SQL Server 对无时分秒的日期字面量默认补
00:00:00,不是四舍五入,也不是取当天最大值 - 如果字段类型是
DATETIME或TIMESTAMP(带时间),绝不能只写日期字符串 - 显式写全时间才能可控:比如
'2024-01-31 23:59:59'仍可能漏掉毫秒级数据(如23:59:59.500),更稳妥的是用左闭右开区间
推荐用左闭右开写法:>= AND
比 BETWEEN 更安全、语义更清晰,也避免时区和精度陷阱。查 2024 年 1 月全部数据,应该写:
WHERE date_col >= '2024-01-01' AND date_col < '2024-02-01'
-
>= '2024-01-01'包含当天 00:00:00.000 起所有值 排除 2 月第一天,自然覆盖到 1 月最后 1 毫秒- 即使字段是
TIMESTAMP WITH TIME ZONE,只要比较值也带同样时区,逻辑不变 - 索引能正常使用,性能不打折
不同数据库对日期字面量的处理差异
看似一样的字符串,在不同系统里隐式转换规则不同:
- MySQL:
'2024-01-01'→DATETIME类型时固定为'2024-01-01 00:00:00' - PostgreSQL:
'2024-01-01'字面量类型是date,和timestamp比较时会自动补00:00:00 UTC(受timezone设置影响) - SQL Server:把
'2024-01-01'当作datetime,值为'2024-01-01 00:00:00.000',但datetime2精度更高,补零行为一致 - Oracle:
DATE类型始终包含时间部分,'2024-01-01'实际是'2024-01-01 00:00:00'
当字段是字符串类型时,BETWEEN 更危险
如果日期存的是 VARCHAR(如 '20240101' 或 '2024-01-01'),BETWEEN 会按字典序比较,不是时间序:
-
BETWEEN '2024-01-01' AND '2024-01-31'在字符串比较下没问题(因为格式统一) - 但
BETWEEN '2024-1-1' AND '2024-1-31'就会出错:字典序中'2024-1-31' (因为 <code>'3''2'?不,其实是'2024-1-31'和'2024-1-2'比较时,前缀相同,第 8 位'3'>'2',但长度不同,实际取决于具体实现,不可靠) - 正确做法永远先转类型:
WHERE CAST(date_str AS DATE) >= '2024-01-01' AND CAST(date_str AS DATE) - 长期看,必须改表结构,把字符串日期转为原生日期类型

















