DATE_SUB(NOW(), INTERVAL N DAY)是最常用且可靠的查询最近N天数据的方法,INTERVAL必须配合DATE_ADD或DATE_SUB使用,不能单独作为值;推荐用>=单边比较而非BETWEEN,语义清晰且索引友好。

MySQL 查询最近 N 天:用 DATE_SUB() 比 INTERVAL 更稳
直接说结论:DATE_SUB(NOW(), INTERVAL N DAY) 是最常用也最可靠的写法,INTERVAL 本身不是函数,不能单独用,必须配合 DATE_ADD() 或 DATE_SUB()。很多人搜“INTERVAL 查询最近几天”,结果写成 WHERE created_at > INTERVAL 7 DAY——这会报错:ERROR 1064,因为 INTERVAL 是操作符,不是值。
正确姿势是把它当作时间偏移量,嵌在日期函数里:
SELECT * FROM orders WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY);
-
NOW()返回当前日期时间(带时分秒),适合需要精确到秒的场景 - 如果只要日期粒度(忽略时间),可用
CURDATE()替代NOW(),避免漏掉当天 00:00:00 之后的记录 -
INTERVAL 7 DAY中的DAY可换成HOUR、MONTH、WEEK等,但注意WEEK是按 7 天算,不自动对齐周几
为什么不用 BETWEEN 写“最近 7 天”?
BETWEEN 看似直观,但容易因边界和时区出问题。比如写成:
WHERE created_at BETWEEN DATE_SUB(NOW(), INTERVAL 7 DAY) AND NOW()
表面没问题,但若 created_at 字段类型是 DATETIME 且有微秒、或数据库时区与应用不一致,NOW() 的毫秒部分可能导致最后一条记录被截断;更隐蔽的是,如果表里存在未来时间(如测试数据或时钟错误),BETWEEN 会把它们也拉进来。
推荐只用单边比较:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
-
>= DATE_SUB(...)—— 明确表达“从某时刻起至今”,语义干净 - 索引能有效命中(前提是
created_at有索引) - 避免
BETWEEN隐含的闭区间陷阱,尤其是和TIMESTAMP类型混用时
DATE_SUB() 和 ADDDATE() 有什么区别?
功能几乎一样,但可读性和兼容性有差异:
-
DATE_SUB(NOW(), INTERVAL 7 DAY)—— 语义清晰:“从现在减去 7 天”,MySQL 官方文档主推写法 -
ADDDATE(NOW(), -7)—— 简洁但反直觉:负数表示减,正数才是加;而且它默认单位是天,想用小时得写ADDDATE(NOW(), INTERVAL -2 HOUR),反而更啰嗦 -
ADDDATE()在旧版本 MySQL(如 5.5)中支持更好,但新项目无需考虑 - 性能无差别,底层都走相同执行路径,选哪个纯看团队习惯
查“最近 7 个自然日”(不含今天)怎么写?
这是实际业务常见需求,比如“过去一周的订单统计”,通常指昨天、前天……倒推 7 天,不包含今天。容易错写成 INTERVAL 7 DAY,结果查的是“今天往前 7 天”,包含了今天。
正确做法是把起点设为 YESTERDAY:
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND created_at
-
CURDATE()返回今天日期(2024-06-15),不带时间,安全 -
DATE_SUB(CURDATE(), INTERVAL 7 DAY)得到2024-06-08,再配合就精准框住2024-06-08到2024-06-14全天 - 别用
DATE_SUB(NOW(), INTERVAL 1 DAY)当起点——它可能返回2024-06-14 23:59:59,漏掉当天 00:00:00–23:59:59 的数据
这个细节在定时任务或日报脚本里特别关键,一不留神就少算一天数据。










