如何用Rails查询按parent_id分组并获取每组最大version的行?
Rails 查询:按parent_id分组并获取每组version最大的行
给定表结构:
| id | parent_id | version | other columns ... | | 1 | 10 | 1 | ... | | 2 | 10 | 2 | ... | | 3 | 23 | 1 | ... | | 4 | 55 | 1 | ... | | 5 | 55 | 2 | ... | | 6 | 55 | 3 | ... |
需要实现:
- 按
parent_id字段分组 - 定位每组中
version值最大的行(无重复版本值) - 优先返回ActiveRecord对象集合,至少能拿到目标行的id数组
期望结果为id=2、3、6的行。
实现方案
方法1:子查询关联(兼容大多数数据库)
先通过分组查询拿到每个parent_id对应的最大版本号,再关联原表筛选出符合条件的记录:
# 替换YourModel为你的实际模型类名 max_version_subquery = YourModel.group(:parent_id).select(:parent_id, 'MAX(version) AS max_version') # 关联子查询,获取目标记录 target_records = YourModel.joins( "JOIN (#{max_version_subquery.to_sql}) AS max_v ON your_models.parent_id = max_v.parent_id AND your_models.version = max_v.max_version" ) # 若只需要id数组 target_ids = target_records.pluck(:id) # => [2, 3, 6]
注:如果你的模型对应的表名不是your_models,需要替换为实际表名。
方法2:窗口函数(Rails 5+,数据库需支持窗口函数如PostgreSQL/MySQL 8+)
用窗口函数按parent_id分区,按version倒序排序后取每组的第一行:
# 替换YourModel为你的实际模型类名 target_records = YourModel.select('your_models.*').from( YourModel.select('your_models.*', 'ROW_NUMBER() OVER (PARTITION BY parent_id ORDER BY version DESC) AS rn') ).where(rn: 1) # 获取id数组 target_ids = target_records.pluck(:id) # => [2, 3, 6]
这种写法更简洁,且能直接返回完整的ActiveRecord对象,适合需要操作模型实例的场景。
补充说明
很多人一开始会尝试直接用group后取整行,但group本质是聚合操作,只能返回分组字段和聚合函数结果,无法直接拿到整行数据,所以需要通过子查询或窗口函数间接实现,这也是这类需求看似简单但容易卡壳的原因。
内容的提问来源于stack exchange,提问作者Grant Birchmeier
相关产品推荐
相关产品推荐

