
本文介绍如何使用 sql 的日期提取函数,精准筛选出数据库中所有与当前日期“同月同日但年份更早”的文章记录,适用于“历史上的今天”类功能开发。
本文介绍如何使用 sql 的日期提取函数,精准筛选出数据库中所有与当前日期“同月同日但年份更早”的文章记录,适用于“历史上的今天”类功能开发。
在构建“历史上的今天”(On This Day)功能时,核心需求是:获取所有创建于当月当日、但年份早于当前年的文章,而非仅限于最近 N 天或某时间范围内的数据。原始代码中错误地使用了 posts.created_at >= CURRENT_DATE 条件,这反而排除了历史年份的数据,逻辑与目标完全相悖。
正确的实现应剥离年份约束,仅比对月份和日期,并明确要求年份小于当前年。以下为优化后的完整方法:
public function get_on_this_day_events($lang_id, $limit)
{
$sql = "SELECT * FROM posts
WHERE
EXTRACT(DAY FROM posts.created_at) = EXTRACT(DAY FROM CURRENT_TIMESTAMP)
AND EXTRACT(MONTH FROM posts.created_at) = EXTRACT(MONTH FROM CURRENT_TIMESTAMP)
AND EXTRACT(YEAR FROM posts.created_at) db->query($sql, array(clean_number($lang_id), clean_number($limit)));
return $query->result();
}
✅ 关键改进说明:
- 使用 EXTRACT(DAY/MONTH/YEAR FROM ...) 精确分离日期组件,跨年匹配更可靠;
- 移除错误的时间下限过滤(如 >= CURRENT_DATE),改用 YEAR
- 补充 lang_id 参数绑定,修复原SQL中占位符缺失导致的参数错位问题;
- 显式添加 ORDER BY ... DESC 和 LIMIT,确保结果按时间倒序排列且可控;
⚠️ 注意事项:
- 确保 posts.created_at 字段为 DATETIME 或 TIMESTAMP 类型,否则 EXTRACT 可能返回异常值;
- 若需支持时区敏感场景,建议将 CURRENT_TIMESTAMP 替换为 CURRENT_DATE AT TIME ZONE 'UTC' 等显式时区表达式;
- 在高并发或大数据量场景下,可为 (EXTRACT(MONTH FROM created_at), EXTRACT(DAY FROM created_at)) 建立函数索引(如 PostgreSQL 支持)以提升查询性能。
该方案简洁、可读性强,且兼容主流 SQL 数据库(PostgreSQL、MySQL 8.0+、SQL Server 等),是实现“历史上的今天”功能的稳健实践。










