最稳妥方式是用 date_sub(now(), interval 7 day) 获取七天前零点时间(如2024-06-10 00:00:00)与 datetime 字段比较,避免用 between 或对字段应用函数导致索引失效。

MySQL 中用 DATE_SUB(NOW(), INTERVAL 7 DAY) 获取最近七天
MySQL 不支持直接写 WHERE date_col >= NOW() - 7 这种模糊表达,必须显式使用日期函数。最稳妥的方式是用 DATE_SUB(NOW(), INTERVAL 7 DAY) 计算七天前的零点时间(即 2024-06-10 00:00:00),再和 datetime 字段比较。
常见错误是用 BETWEEN NOW() - INTERVAL 7 DAY AND NOW(),但 BETWEEN 是闭区间,且 NOW() 包含秒级精度,容易漏掉今天最后几秒的数据;更推荐用左闭右开:date_col >= DATE_SUB(NOW(), INTERVAL 7 DAY) AND date_col 。
- 如果字段是
DATE类型(无时间部分),可用date_col >= DATE_SUB(CURDATE(), INTERVAL 6 DAY)—— 注意是 6 天,因为CURDATE()返回今天日期,往前推 6 天刚好覆盖 7 个自然日 - 避免在 WHERE 中对字段用函数,比如
DATE(date_col) >= ...,会导致索引失效 -
NOW()和CURDATE()都受 session 时区影响,确认SELECT @@time_zone是否符合业务预期
PostgreSQL 里用 current_date - INTERVAL '6 days'
PostgreSQL 的日期运算更直观,但要注意:想查“最近七天”(含今天),起始日期是今天减去 6 天,不是 7 天。因为 current_date - INTERVAL '6 days' 到 current_date 正好是 7 个日期点(例如 6月4日~6月10日)。
若字段是 TIMESTAMP WITH TIME ZONE,直接比较即可;如果是 TIMESTAMP WITHOUT TIME ZONE,需注意是否隐含本地时区含义。
- 推荐写法:
created_at >= (current_date - INTERVAL '6 days')::timestamp AND created_at ,确保覆盖今天全部时间 - 别写
created_at::date >= current_date - 6,类型转换会阻止索引使用 - PostgreSQL 中
NOW()返回带时区的时间戳,比current_date更精确,但要注意时区一致性
SQL Server 中用 DATEADD(day, -6, GETDATE()) 要小心时区与精度
SQL Server 默认用服务器本地时区,GETDATE() 返回 datetime(精度到 3.33ms),而 SYSDATETIME() 更精确(100ns)。查最近七天通常用 DATEADD(day, -6, CAST(GETDATE() AS DATE)) 起始,再拼上时间边界。
典型陷阱是直接用 date_col >= DATEADD(day, -7, GETDATE()),这会从当前时刻往前推 7 天,导致每天查询范围长度不一致(比如今天 15:30 查询,就只查 15:30 之后的七天数据)。
- 正确做法:先截断到日期,再加时间边界 ——
date_col >= DATEADD(day, -6, CAST(GETDATE() AS DATE)) AND date_col - 如果字段是
datetime2,建议统一用SYSDATETIME()避免精度丢失 - 跨时区部署时,优先考虑
GETUTCDATE()并在应用层做时区转换,而非依赖服务器本地时间
通用注意事项:字段类型、索引与夏令时
无论哪种数据库,“最近七天”的语义必须和字段类型对齐:是按日历日(calendar day)、按 24 小时滚动窗口,还是按业务日(如凌晨 4 点为一天开始)?这个定义决定了起始时间点怎么算。
性能上,只要 WHERE 条件没对字段本身做函数操作(如 YEAR(col)、CONVERT(DATE, col)),B-tree 索引就能生效。但一旦用了函数或类型转换,基本等于全表扫描。
- 夏令时切换当天,用本地时间计算可能跳过或重复一小时数据,生产环境建议统一用 UTC 存储和查询
- SQLite 没有原生日期函数,得靠
date('now', '-6 days'),且只支持整数天,不能写'-6.5 days' - Oracle 用户注意:
SYSDATE - 7是合法的,但它是按 24 小时算,不是日历日;要用TRUNC(SYSDATE) - 6才对齐自然日
真正难的不是写出语法,而是确认“最近七天”在你系统里到底指什么时间粒度、哪个时区、是否包含未结束的今天——这些细节定不下来,SQL 写得再对也没用。











