You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Rails 6中如何按X列去重取最新记录并对Y列求和

解决方案

问题原因

你使用的Table.distinct(:x).sum(:y)不符合预期,是因为Rails的distinct方法仅支持传入布尔值控制是否开启全局去重,传入:x并不会实现「按x字段分组仅保留唯一值」的逻辑,最终生成的SQL会对全表所有行去重,自然会把X=A的旧记录纳入求和范围。

正确实现方式

方案1:窗口函数实现(推荐,兼容PG、MySQL 8.0+等主流现代数据库)

通过ROW_NUMBER窗口函数给每个x分组内的记录按创建时间倒序排名,取排名为1的最新记录后再求和,执行效率最高,适合数据量较大的场景:

# 给每个x分组的记录标注排名,created_at越新排名越靠前
ranked_records = Table.select(
  "*, ROW_NUMBER() OVER (PARTITION BY x ORDER BY created_at DESC, id DESC) AS row_rk"
)
# 仅取每个x的最新记录,再对y求和
sum_y = Table.from(ranked_records, "ranked").where("ranked.row_rk = 1").sum(:y)

补充:排序规则增加id DESC是为了处理同个x存在多条created_at完全相同的记录的边界场景,确保取到的是最后插入的那条记录。

方案2:分组关联实现(兼容低版本MySQL等不支持窗口函数的数据库)

先查询每个x对应的最新创建时间,再关联回原表匹配到对应记录后求和:

# 先获取每个x对应的最新创建时间
latest_time_per_x = Table.group(:x).select("x, MAX(created_at) AS latest_created")
# 关联原表匹配到最新记录后求和
sum_y = Table.joins(
  "INNER JOIN (#{latest_time_per_x.to_sql}) latest ON tables.x = latest.x AND tables.created_at = latest.latest_created"
).sum(:y)

注意事项

如果你的实际表名就是table(和SQL关键字冲突),编写原生SQL片段时需要给表名加反引号转义,避免语法报错。

结果验证

对你提供的样例数据,两种方案执行后得到的求和结果均为9(去重后保留的记录为A:1、B:5、C:3,求和1+5+3=9),符合需求预期。

内容的提问来源于stack exchange,提问作者jdk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 09:48:05