在MySQL的业务查询中,按距离当前日期最近排序是常见需求,比如展示最近发布的商品、即将截止的订单等,核心是通过计算日期差值后排序实现。

核心实现原理
实现该排序的核心是DATEDIFF函数,该函数用于计算两个日期之间的天数差,语法为DATEDIFF(date1, date2),返回date1减去date2的天数。结合ORDER BY子句对差值排序,就能得到距离当前日期最近的记录。
基础排序实现
假设有一张article表,包含id、title、publish_date字段,需要按发布时间距离当前日期最近排序,基础查询语句如下:
-- 查询文章并按距离当前日期最近排序,最近的排在最前 SELECT id, title, publish_date FROM article ORDER BY DATEDIFF(CURDATE(), publish_date) ASC;
这里CURDATE()获取当前日期,DATEDIFF(CURDATE(), publish_date)计算当前日期和发布日期的天数差,差值越小说明发布时间越近,所以使用ASC升序排列。
包含未来日期的排序场景
如果表中存在未来日期的记录,比如任务表的deadline字段,需要把最近的未来日期也排在前面,此时可以用绝对值计算差值:
-- 查询任务,按距离当前日期最近排序,过去和未来最近的都靠前 SELECT id, task_name, deadline FROM task ORDER BY ABS(DATEDIFF(CURDATE(), deadline)) ASC;
ABS()函数取绝对值,这样不管是过去还是未来的日期,和当前日期的差值绝对值越小,排序越靠前。
特殊场景处理
处理日期字段为NULL的情况
如果日期字段存在NULL值,DATEDIFF计算结果为NULL,排序时NULL会排在最前或最后,不符合预期。可以用COALESCE函数给NULL设置默认值:
-- 处理publish_date为NULL的情况,默认用当前日期计算 SELECT id, title, publish_date FROM article ORDER BY DATEDIFF(CURDATE(), COALESCE(publish_date, CURDATE())) ASC;
这里COALESCE(publish_date, CURDATE())表示如果publish_date为NULL,就用当前日期代替,避免排序异常。
性能优化建议
如果表数据量较大,对日期字段直接计算函数会导致索引失效,可以在表中新增一个冗余字段存储日期对应的时间戳,或者创建函数索引(MySQL 8.0+支持):
-- MySQL 8.0+ 创建函数索引优化排序性能 CREATE INDEX idx_publish_date_diff ON article ((DATEDIFF(CURDATE(), publish_date)));
常见误区说明
不要误用ORDER BY publish_date DESC来实现最近排序,这种方式只能按日期从新到旧排,无法处理未来日期的场景,也不符合距离当前日期最近的逻辑。另外计算差值时要注意日期顺序,DATEDIFF(CURDATE(), date)和DATEDIFF(date, CURDATE())的结果符号相反,排序方向也会相反。
注意:CURDATE()获取的是当前日期,不包含时间部分,如果需要精确到时间,可以换成NOW()函数,同时日期字段需要是datetime或timestamp类型。