SQL日期比较三大陷阱:一是字符串格式化比较导致索引失效,应改用左闭右开时间范围;二是单日查询边界错误,须用>=起始时间且

SQL 里日期比较看着简单,实际最容易掉进逻辑陷阱。三个最常踩、又不报错的坑,直接影响数据准确性。
坑一:用字符串格式化后做比较
比如写 DATE_FORMAT(create_time, '%Y-%m') = '2026-01',表面看是查 1 月数据,其实是在比字符串——不是时间范围,而是字典序匹配。一旦字段带毫秒、或数据库对隐式转换处理不同,结果就不可靠;更关键的是,create_time 上的索引完全失效,查询变慢还查不准。
正确做法是保持时间类型不变,用范围表达:
- create_time >= '2026-01-01 00:00:00'
- create_time
左闭右开,精准覆盖整月,还能走索引。
坑二:边界写错导致漏数据或跨天
想查“2026-01-18 当天”,写成 log_time = '2026-01-18',只命中 00:00:00 那一刻;写成 log_time ,可能因毫秒/微秒精度被截断而漏掉末尾几条记录。
稳妥写法始终用“起始时间 ≤ x
- log_time >= '2026-01-18 00:00:00'
- log_time
哪怕字段是 DATETIME 或 TIMESTAMP,这个逻辑都通用、无歧义。
坑三:忽略时区和字段类型差异
数据库存的是 UTC 时间,但你用 CURDATE() 或 '2026-01-18' 直接比,相当于拿本地时区的日期去比 UTC 时间戳——在北京时间下午查,可能把当天上午刚入库的记录判为“昨天”。
另外,字段是 DATE 类型却拿来跟含时间的字符串(如 '2026-01-18 10:00:00')比较,有些数据库会自动补零,有些则隐式转成时间再比,行为不一致。
建议统一策略:
- 存储用 UTC,查询时用 CONVERT_TZ() 或应用层转换后再比
- 明确字段类型:DATE 类型就只跟 'YYYY-MM-DD' 比;DATETIME/TIMESTAMP 必须带完整时间部分
不复杂但容易忽略










