date_sub(now(), interval 1 day) 是最稳妥的取昨天日期字符串方法,不依赖时区、避免隐式数字转换错误,且兼容datetime精度需求。

MySQL里用 DATE_SUB(NOW(), INTERVAL 1 DAY) 最稳
直接取昨天的日期字符串,DATE_SUB(NOW(), INTERVAL 1 DAY) 是首选。它不依赖时区设置(只要服务器时区一致),也不受 NOW() 和 CURDATE() 返回精度差异影响。
常见错误是写成 NOW() - INTERVAL 1 DAY —— 看似等价,但 MySQL 在某些版本或严格模式下会隐式转成数字计算,导致结果错乱(比如变成 20240509.0 这类非法日期)。
-
DATE_SUB(CURDATE(), INTERVAL 1 DAY)也行,但CURDATE()只返回日期部分,如果业务逻辑依赖“带时间的昨日起点”,得补CAST(... AS DATETIME) - 别用
DATE(NOW() - INTERVAL 1 DAY):先减再截断,多一次类型转换,无必要且易混淆 - 如果字段是
DATETIME类型且要查“昨天全天”,记得用范围查询:WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL 1 DAY) AND created_at
PostgreSQL 怎么写等效语句:用 CURRENT_DATE - INTERVAL '1 day'
PostgreSQL 没有 DATE_SUB,但支持直接对日期做算术运算,CURRENT_DATE - INTERVAL '1 day' 是最自然写法。注意单引号和单位必须小写('1 day'),写成 '1 DAY' 或 '1days' 会报错。
容易踩的坑是混用 NOW():它返回 TIMESTAMP WITH TIME ZONE,减完仍是带时区的时间戳;若字段是 DATE 类型,建议显式截断:(NOW() - INTERVAL '1 day')::DATE,避免隐式转换出问题。
- 用
CURRENT_DATE更安全——它本身就是DATE类型,减完还是DATE - 如果表里存的是
TIMESTAMP且要查“昨天 00:00:00 到 23:59:59”,推荐:WHERE created_at >= (CURRENT_DATE - INTERVAL '1 day') AND created_at - 别用
DATE_PART('day', NOW()) - 1:这是取“今天是几号”,不是“昨天日期”,跨月就崩(比如 1 号减 1 得 0)
WHERE 条件里直接写函数,性能可能掉坑里
在 WHERE 子句里对字段调用函数(比如 DATE(created_at) = DATE_SUB(CURDATE(), INTERVAL 1 DAY))会让索引失效——MySQL 无法用上 created_at 上的普通 B-tree 索引。
正确做法是把函数挪到右边,让左边保持字段原样:
WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL 1 DAY) AND created_at <p>这个写法能命中索引(前提是 <code>created_at</code> 有索引),尤其当数据量大时,响应时间可能从秒级降到毫秒级。</p>
- 如果字段类型是
DATE,且只存日期(无时间),那= CURDATE() - INTERVAL 1 DAY是安全的,也能走索引 - 别信“加函数索引就能解决”:MySQL 5.7+ 虽支持函数索引,但维护成本高,不如改写查询逻辑
- 上线前务必用
EXPLAIN看key和rows字段,确认是否真用了索引
跨数据库移植时,DATE_SUB 和 INTERVAL 写法不通用
SQL 标准没统一日期运算语法,DATE_SUB 是 MySQL 特有,PostgreSQL 用 - INTERVAL,SQL Server 用 DATEADD(day, -1, GETDATE()),SQLite 用 date('now', '-1 day')。硬写死一种,换库就得全改。
如果项目要兼容多数据库,要么用 ORM 层抽象(如 SQLAlchemy 的 func.current_date() - text("INTERVAL '1 day'")),要么在应用层生成日期字符串再传入 SQL(比如 Python 里用 (datetime.today() - timedelta(days=1)).strftime('%Y-%m-%d'))。
- 纯 SQL 迁移时,最省事的是统一用字符串参数:
WHERE date_col = ?,由程序算好昨天日期传进去 - 别试图用
CASE WHEN @@version LIKE '%MySQL%' THEN ... ELSE ... END:SQL 层做数据库判断不可靠,且可读性差 - 测试阶段一定要在目标数据库上跑一遍,光看语法不报错不代表结果对——比如 SQLite 的
date('now')默认按 UTC,而 MySQL 默认按系统时区
事情说清了就结束










