首页/数据/SQL 速查/日期范围查询的边界写法
函数速查60 条

日期范围查询的边界写法

按时间过滤推荐半开区间 [起点, 次日):用 < 下月 1 日 而不是 BETWEEN ... 月末 23:59:59,避免漏掉毫秒数据。

SQL 速查数据更新于 2026-10-13

日期范围边界怎么取

按时间过滤推荐半开区间 [起点, 下一天或下月):created_at >= '2024-06-01' AND created_at < '2024-07-01'。写成 BETWEEN '2024-06-01' AND '2024-06-30' 会漏掉 6 月 30 日当天带时分秒的数据,因为 '2024-06-30' 等价于那天的 00:00:00。

基本信息

推荐写法左闭右开:>= 起点 AND < 终点
原因带时间的列上用闭区间会漏掉当天剩余时段的数据
DATE 列例外列本身是 DATE 类型时,BETWEEN a AND b 是安全的
索引范围条件能走 B+ 树索引,前提是过滤列没有被函数包裹
月末处理终点统一写下个月 1 日,不必计算当月天数
时区按天过滤前先确认以哪个时区作为日界

推荐写法

推荐写法
-- 2024 年 6 月整月:包含当月最后一天的每一秒与毫秒
SELECT * FROM orders
WHERE created_at >= '2024-06-01'
  AND created_at <  '2024-07-01';

-- 单日:同样用次日作为开区间上界
SELECT * FROM orders
WHERE created_at >= '2024-06-15'
  AND created_at <  '2024-06-16';

常见错误写法

常见错误写法
-- 漏数据:'2024-06-30' 等于当天 00:00:00,6-30 09:00 的记录不会被返回
SELECT * FROM orders
WHERE created_at BETWEEN '2024-06-01' AND '2024-06-30';

-- 月末日期写错:6 月没有 31 日,语义已偏,严格模式还可能直接报错
SELECT * FROM orders
WHERE created_at BETWEEN '2024-06-01' AND '2024-06-31';

常见写法对比

写法结果评价
BETWEEN a AND b闭区间,两端都含DATE 列安全;DATETIME 列漏月末当天
>= a AND < b左闭右开推荐,任何时间精度都正确
>= a AND <= '23:59:59'右端精度不足毫秒与微秒记录仍会被漏掉
DATE(col) = '2024-06-01'只命中当天 00:00:00语义错,且列上包函数导致索引失效
DATE(col) BETWEEN …能表达按天范围列被函数包裹,索引同样用不上

典型使用场景

  • 日报周报月报的取数范围定义
  • 分批导出历史数据:按创建时间切片逐步导出
  • 对账:取某个自然月的全部流水
  • 增量同步:用上次同步时间点作为左边界
  • 数据清理:删除某时间点之前的数据,删除前先确认边界与行数
  • 监控告警统计:取最近 24 小时或者最近 7 整天
想按自然月取数,与其计算月末是 28 还是 31 日,不如直接写下个月 1 日作为上界;也可以用日期函数动态生成两个边界,注意别在过滤列本身上包函数。
跨时区按天过滤要先统一日界:存储是 UTC、业务按北京时间看日报时,边界必须换算成对应的 UTC 时刻,否则首尾那一小时的数据会被算错。

易错点

  • 用 BETWEEN 取某个整月:DATETIME 列会漏掉月末当天的数据,改成左闭右开区间
  • 右端写 23:59:59:毫秒与微秒精度的记录仍然漏掉,直接写次日零点更彻底
  • 在过滤列上包 DATE() 函数:索引失效退化为全表扫描,改写成范围条件
  • 跨时区直接套用本地日期边界:首尾小时的数据会被漏算或多算
  • 月末日期硬编码 30 或 31:2 月与大小月会出错,统一取下月 1 日

数据来源与参考

  • MySQL 8.0 Reference Manual · Date and Time Functions
  • PostgreSQL Documentation · Date/Time Functions and Operators
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌