如何优化ActiveRecord查询以获取MySQL中loco_no列的唯一最新记录
优化ActiveRecord查询获取每个loco_no的最新记录
要实现每个loco_no只返回最新(按updated_at降序)的is_live: true记录,这里有几种可靠的方案,根据你使用的数据库选择最适合的:
方案一:PostgreSQL专属(简洁高效)
PostgreSQL支持DISTINCT ON语法,能直接按指定字段分组并取每组的第一条记录:
LocoUpdate.where(is_live: true) .order(:loco_no, updated_at: :desc) # 先按loco_no分组,组内按updated_at倒序 .distinct_on(:loco_no) # 保留每个loco_no的第一条记录
这个查询会先把所有符合条件的记录按loco_no分组,每组内按updated_at从新到旧排序,然后只保留每组的第一条,完美匹配你的需求。
方案二:跨数据库兼容(用窗口函数)
如果你的项目需要兼容MySQL、SQLite等其他数据库,窗口函数ROW_NUMBER()是更通用的选择:
# 子查询:给每个loco_no分组的记录添加行号,最新的记录行号为1 subquery = LocoUpdate.where(is_live: true) .select( "loco_updates.*", "ROW_NUMBER() OVER (PARTITION BY loco_no ORDER BY updated_at DESC) AS rn" ) # 外层查询:筛选出行号为1的记录 LocoUpdate.from("(#{subquery.to_sql}) AS loco_updates") .where(rn: 1)
原理是通过窗口函数给每个loco_no下的记录按updated_at倒序分配行号,然后只保留行号为1的那条,也就是每个分组的最新记录。
方案三:基于ID的分组(需谨慎使用)
如果你的LocoUpdate表中,updated_at最晚的记录对应的id也最大(比如默认的自增ID),可以用更简单的分组查询:
# 先获取每个loco_no对应的最新记录ID latest_ids = LocoUpdate.where(is_live: true) .group(:loco_no) .select("MAX(id) AS id") # 通过ID查询完整记录 LocoUpdate.where(id: latest_ids)
⚠️ 注意:这个方法仅当id的增长和updated_at的更新完全同步时才可靠,如果存在同一时间多条记录或者ID不按时间递增的情况,可能会返回错误的结果。
以上几种方法都能帮你得到期望的结果:每个loco_no仅保留最新的那条is_live: true的记录,和你给出的示例结果一致。
内容的提问来源于stack exchange,提问作者muskrat_
相关产品推荐
相关产品推荐

