mysql用date_sub(now(), interval 30 day)最稳,postgresql用current_date - interval '30 days',sql server用dateadd(day, -30, getdate()),需注意索引、时区及字段类型匹配。

MySQL里用DATE_SUB和NOW()取最近30天
直接用 WHERE create_time >= DATE_SUB(NOW(), INTERVAL 30 DAY) 最稳。注意别写成 DATE_SUB(NOW(), INTERVAL 30 DAY) 后面漏掉 TIME 部分——NOW() 返回的是带时分秒的完整时间戳,DATE_SUB 会原样减去30天,结果仍是带时间的,能准确匹配到毫秒级数据。
常见错误是写成 create_time >= '2024-05-01' 这种硬编码,或者误用 DATE(NOW()) 先截断时间再减,导致当天0点之后的数据被漏掉。
- 如果字段是
DATETIME或TIMESTAMP类型,直接用上面的写法即可 - 如果字段是
DATE类型(只有年月日),可以写成create_date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY),更清爽 - 别用
BETWEEN包含“今天”和“30天前”,容易因时区或凌晨执行导致边界错位
PostgreSQL用CURRENT_DATE和INTERVAL
PostgreSQL不认 DATE_SUB,得用 CURRENT_DATE - INTERVAL '30 days'。注意单引号里必须是 '30 days'(复数),写成 '30 day' 会报错:ERROR: invalid input syntax for type interval。
如果表里存的是 TIMESTAMP WITH TIME ZONE,建议统一转成日期比较,避免时区干扰:
WHERE created_at::DATE >= CURRENT_DATE - INTERVAL '30 days'
但要注意 ::DATE 强制转换会丢失索引,如果查询频繁且数据量大,最好在 created_at 上建函数索引:
CREATE INDEX idx_created_at_date ON orders ((created_at::DATE));
SQL Server用DATEADD别踩GETDATE()陷阱
SQL Server 必须用 DATEADD(day, -30, GETDATE()),不是 DATEADD(-30, day, GETDATE())——参数顺序固定,反了就语法错误。
另一个坑是 GETDATE() 返回本地服务器时间,如果业务跨时区,可能和应用层时间对不上。更稳妥的方式是用 SYSDATETIMEOFFSET() 配合 AT TIME ZONE 转换:
WHERE event_time >= DATEADD(day, -30, SYSDATETIMEOFFSET() AT TIME ZONE 'China Standard Time')
但多数内部系统用 GETDATE() 就够了,前提是数据库和应用部署在同一时区。
- 别用
DATEPART拆年月日再拼字符串,性能差还难维护 - 如果字段是
SMALLDATETIME,精度只到分钟,DATEADD结果也自动对齐,不用额外处理
通用提醒:索引、时区和字段类型三连问
写完条件别急着跑,先看这三点:
- 查一下
create_time字段有没有索引——没索引的话,30天只是过滤条件,全表扫描照旧 - 确认数据库时区和业务期望是否一致,特别是用
NOW()/GETDATE()/CURRENT_TIMESTAMP的时候 - 字段是
TIMESTAMP还是DATETIME?MySQL 中前者自动转时区,后者存什么就是什么,影响实际范围
最常被忽略的是字段类型隐式转换:比如 create_time 是 VARCHAR 存的日期字符串,加了函数后必然无法走索引,而且可能因格式不统一('2024/05/01' vs '2024-05-01')导致漏数据。











