date_sub函数需按date、interval expr unit顺序使用,mysql特有,单位须大写;where中日期字段应居左避免函数包裹以保障索引;跨库需改用对应语法。

DATE_SUB函数的基本用法和参数顺序
DATE_SUB 是 MySQL 提供的日期运算函数,用来从指定日期减去一个时间间隔。它有两个必需参数:date 和 INTERVAL expr unit,顺序不能颠倒——先写日期,再写间隔表达式。常见错误是把 INTERVAL 写在前面,或者漏掉 INTERVAL 关键字,导致报错 ERROR 1064。
比如想查“今天往前推30天”,正确写法是:
DATE_SUB(CURDATE(), INTERVAL 30 DAY)
注意:CURDATE() 返回的是日期(不含时间),如果字段是 DATETIME 类型且含具体时分秒,用 NOW() 更稳妥,否则可能漏掉当天零点后的记录。
WHERE条件中怎么写才能准确覆盖最近30天
直接用 WHERE date_col >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) 看似合理,但容易出问题:如果 date_col 是 DATETIME 类型,而 CURDATE() 返回的是 2024-05-20,那这个条件实际等价于 >= '2024-05-20 00:00:00',会包含今天全天,但“最近30天”通常指从当前时刻往前推720小时,不是按日历日切分。
- 要严格按“过去30×24小时”算,用
NOW():date_col >= DATE_SUB(NOW(), INTERVAL 30 DAY) - 如果业务上真按自然日(比如报表统计每天0点到24点),且字段是
DATE类型,CURDATE()没问题 - 别用
BETWEEN包裹起止,因为BETWEEN a AND b是闭区间,而“最近30天”一般不包含更早那天的0点,容易多包一天
不同数据库对DATE_SUB的支持差异
DATE_SUB 是 MySQL 特有函数,在 PostgreSQL、SQL Server 或 SQLite 中不能直接用。如果你在迁移或跨库写脚本,得换写法:
- PostgreSQL:用
current_date - INTERVAL '30 days'或now() - INTERVAL '30 days' - SQL Server:用
DATEADD(day, -30, GETDATE()) - SQLite:用
datetime('now', '-30 days')
MySQL 8.0+ 支持标准 SQL 的 DATE_SUB(date, INTERVAL n unit),但低版本(如 5.7)也支持,兼容性好;不过单位必须是全大写,比如 DAY 不能写成 day 或 days,否则报错 ERROR 1064。
性能坑:别在WHERE里对字段用DATE_SUB
常见误写:WHERE DATE_SUB(NOW(), INTERVAL 30 DAY) 看起来一样,但函数作用在右边常量上,不影响索引;可一旦写成 <code>WHERE DATE_SUB(date_col, INTERVAL 30 DAY) >= '2024-01-01',就让 date_col 被函数包裹,MySQL 无法走索引,全表扫描风险很高。
务必保证日期字段出现在比较运算符的左侧,且不被任何函数包裹。如果实在要转换字段值(比如统一转成本地时区),优先考虑在写入时归一化存储,而不是查询时计算。
真正容易被忽略的,是字段类型和函数返回类型的隐式匹配——DATE_SUB(CURDATE(), ...) 返回 DATE,跟 DATETIME 字段比较时会自动补 00:00:00,但这个转换在某些严格模式下会告警,也可能影响执行计划。











