Rails带条件Distinct查询:按created_at取各status_type最新记录
注意:示例数据中created_at存在非法日期格式笔误,以下方案默认表中created_at为标准datetime/timestamp类型,可正常进行时间大小比较、排序操作。
以下是不同场景下可用的Rails查询写法,最终都会返回status_type为test、integer的2条最新记录:
PostgreSQL 环境(Rails 最常用搭配)
使用PG原生的DISTINCT ON语法实现,性能最优,写法最简洁:
# 将YourModel替换为实际对应的模型名即可 result = YourModel .select("DISTINCT ON (status_type) *") .where(status_type: ["test", "integer"]) .order("status_type, created_at DESC")
MySQL 8.0+ / 支持窗口函数的数据库环境
通过ROW_NUMBER()窗口函数按status_type分组、组内按创建时间倒序排序,取每组第一条:
result = YourModel .from( YourModel .select("*, ROW_NUMBER() OVER (PARTITION BY status_type ORDER BY created_at DESC) AS row_num") .where(status_type: ["test", "integer"]), :grouped_records ) .where("grouped_records.row_num = 1")
低版本MySQL / 全数据库通用写法
先子查询查出每个status_type对应的最新创建时间,再关联原表匹配出完整记录:
latest_time_subquery = YourModel .group(:status_type) .select(:status_type, "MAX(created_at) AS latest_created_at") result = YourModel .joins("INNER JOIN (#{latest_time_subquery.to_sql}) AS latest_match ON latest_match.status_type = #{YourModel.table_name}.status_type AND latest_match.latest_created_at = #{YourModel.table_name}.created_at") .where(status_type: ["test", "integer"])
注意:如果同一个status_type下存在多条created_at时间完全一致的记录,通用写法会返回所有同时间的匹配记录。Rails默认生成的created_at带微秒级精度,正常业务场景下几乎不会出现这类冲突,如果有强一致性要求,可以追加主键id的倒序排序规则做二次校验。
内容的提问来源于stack exchange,提问作者Devalo
相关产品推荐
相关产品推荐

