mysql大于当前时间置顶升序,小于当前时间的置尾降序

SELECT

    mpr.id,

    mpr.close_time,

    mpr.project_start_time

FROM

    merchant_project_record mpr

ORDER BY 

    mpr.close_time < NOW()

    IF(mpr.close_time < NOW(), 0, mpr.close_time)

    mpr.close_time DESC

LIMIT 0,10;


1. 排序逻辑分析

mpr.close_time < NOW():返回一个布尔值(0 或 1),表示时间是否已经过期。

IF(mpr.close_time < NOW(), 0, mpr.close_time):如果时间已过期,用 0 替代;否则保留原始时间。

最终排序规则:

第一优先级:是否过期(未过期在前,过期在后)。

第二优先级:未过期的时间越早排在前面(因为 mpr.close_time DESC 是降序)。

第三优先级:mpr.close_time 降序。

2. 分页重复的原因

当使用 LIMIT offset, size 进行分页时,如果多条记录的排序字段完全相同(比如多个记录的 close_time 相同且都未过期),数据库无法保证这些记录的顺序稳定性,从而可能导致上一页最后一条记录与下一页第一条记录重复。


解决方案

✅ 方法一:增加唯一排序字段

为了确保排序唯一性,建议在 ORDER BY 中加入唯一字段(如主键 id)作为最后一级排序条件:

SELECT mpr.id, mpr.close_time

FROM merchant_project_record mpr

ORDER BY

    mpr.close_time < NOW(),

    IF(mpr.close_time < NOW(), 0, mpr.close_time),

    mpr.close_time DESC,

    mpr.id DESC -- 增加主键作为最终排序依据

LIMIT 0,10;

这样可以确保即使其他排序字段相同,也能通过 id 确保每条记录的唯一位置。


✅ 方法二:使用游标分页(Cursor-based Pagination)

如果你对性能要求较高,推荐使用 游标分页,避免偏移量带来的性能和重复问题。

假设上一页最后一条记录的 close_time = '2025-04-01 00:00:00', id = 100,那么下一页查询可以写为:

SELECT mpr.id, mpr.close_time

FROM merchant_project_record mpr

WHERE

    (mpr.close_time < NOW()) = 0 AND mpr.close_time >= '2025-04-01 00:00:00' AND mpr.id < 100

    OR

    (mpr.close_time < NOW()) = 0 AND mpr.close_time > '2025-04-01 00:00:00'

ORDER BY

    mpr.close_time < NOW(),

    IF(mpr.close_time < NOW(), 0, mpr.close_time),

    mpr.close_time DESC,

    mpr.id DESC

LIMIT 10;

这种方式可以避免传统分页中因排序不稳定导致的数据重复或丢失。


总结


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。