<p>最快捷写法是直接用DATEDIFF等函数计算天数差,但需注意MySQL与SQL Server参数顺序相反;PostgreSQL推荐created_at < NOW() - INTERVAL '5 days'以走索引;Oracle直接相减最简洁;跨库应避免函数包裹字段,改用范围条件。</p>

WHERE 子句里用 DATEDIFF 计算天数差(MySQL / SQL Server)
直接用 DATEDIFF 函数比较当前时间和字段时间,是最快捷的写法。但要注意函数参数顺序:MySQL 是 DATEDIFF(NOW(), create_time)(大减小),SQL Server 是 DATEDIFF(day, create_time, GETDATE())(小减大),顺序反了会得到负值,导致条件失效。
常见错误现象:查不到数据,但手工验算明明已超时——大概率是参数顺序写反,或误用了 TIMESTAMPDIFF(MySQL)却没指定单位。
使用场景:筛选创建超过 7 天未处理的工单
示例(MySQL):
SELECT * FROM orders WHERE status = 'pending' AND DATEDIFF(NOW(), created_at) > 7;
注意:NOW() 在执行时求值,不是语句开始时;如果查询耗时长,同一语句内多次调用可能有微小偏差(通常可忽略)。
PostgreSQL 用 age() 或普通减法(不依赖函数名统一)
PostgreSQL 没有 DATEDIFF,但支持直接用时间相减,返回 interval 类型,再用 EXTRACT 提取天数:
SELECT * FROM tasks WHERE status = 'new' AND EXTRACT(DAY FROM NOW() - created_at) > 5;
也可以用 age(),但 age(NOW(), created_at) 返回的是带年月日的 interval,不如直接减法直观。
容易踩的坑:
- 忘记
EXTRACT(DAY FROM ...),直接写NOW() - created_at > INTERVAL '5 days'虽然也对,但可读性差,且在某些 ORM 中解析困难 - 用
created_at < NOW() - INTERVAL '5 days'更推荐——它能走索引,而EXTRACT(...)会导致字段被函数包裹,无法使用created_at上的索引
Oracle 用日期直接相减(结果是天数浮点数)
Oracle 中两个 DATE 类型相减,结果就是以“天”为单位的数值(含小数),所以判断逻辑最简洁:
SELECT * FROM alerts WHERE status = 'unhandled' AND SYSDATE - created_date > 3;
关键点:
- 不要用
TO_DATE(SYSDATE)或其他转换,SYSDATE本身就是 DATE 类型 - 如果
created_date是TIMESTAMP,相减仍有效,但精度到秒,结果是小数(比如 3.00012),和整数比较时建议用>= 3或> 2.999避免边界误差 - 索引友好:该写法不改变字段形式,
created_date上的索引可正常生效
跨数据库兼容写法:用范围条件代替函数包裹字段
如果项目要兼容多种数据库,或者表数据量大、有性能要求,优先避免在字段上套函数。统一改写为“字段小于某个时间点”:
-- 所有主流数据库都支持 SELECT * FROM jobs WHERE status = 'queued' AND created_at < NOW() - INTERVAL '10 days'; -- MySQL / PostgreSQL
Oracle 写成:
AND created_at < SYSDATE - 10;
SQL Server:
AND created_at < DATEADD(day, -10, GETDATE());
这种写法的关键优势是:所有数据库都能对 created_at 字段使用索引。而一旦写成 DATEDIFF(NOW(), created_at) > 10,MySQL 和 SQL Server 就没法走索引了。
复杂点在于不同数据库的“减法语法”不一致,但只要把计算逻辑移到右边常量侧,就绕开了函数位置陷阱。上线前务必确认目标库的日期字面量格式和运算符支持——比如 SQLite 用 datetime('now', '-10 days'),就不能混用 INTERVAL。

















