Rails 3.2迁移至5.1:distinct查询调用find_each报错问题
解决Rails 5.1中
find_each因自定义select缺少主键的错误 问题原因
Rails 5.0+ 对find_each的机制做了更严格的校验——这个方法依赖模型的主键字段来实现有序的分批查询(避免重复或遗漏记录)。你当前的select('DISTINCT batch_id')只返回了batch_id,没有包含模型的主键(比如id),所以触发了ArgumentError。
解决方案
根据你的业务需求,有两种常用的处理方式:
方案1:在select中包含主键,同时保证batch_id的唯一性
如果你需要保留SalesActivity实例的操作(而不只是batch_id的值),可以修改select语句,把主键和batch_id一起选中,同时用合适的语法确保batch_id唯一:
- 如果你用的是PostgreSQL,推荐用
DISTINCT ON(会返回每个batch_id对应的第一条记录):
sales = SalesActivity.select('DISTINCT ON (batch_id) batch_id, id, salesperson_id') .where(salesperson_id: sales_id) .order(:batch_id) sales.find_each(batch_size: 2000) do |batchToProcess| # 你的处理逻辑 end
- 如果是MySQL环境,可以用
GROUP BY实现类似效果:
sales = SalesActivity.select('batch_id, id, salesperson_id') .where(salesperson_id: sales_id) .group(:batch_id) sales.find_each(batch_size: 2000) do |batchToProcess| # 你的处理逻辑 end
方案2:先获取唯一的batch_id数组,再手动分批处理
如果你的业务只需要batch_id的值,不需要操作SalesActivity实例,那更高效的方式是用pluck先拿到所有唯一的batch_id,再手动分批:
# 先获取所有唯一的batch_id数组 unique_batch_ids = SalesActivity.where(salesperson_id: sales_id) .distinct.pluck(:batch_id) # 手动按2000条分批处理数组 unique_batch_ids.each_slice(2000) do |batch_ids| # 这里可以根据batch_ids批量处理逻辑,比如: # SalesActivity.where(batch_id: batch_ids).find_each do |activity| ... end end
补充说明
Rails 3.2的find_each实现没有强制检查主键是否存在,它会尝试用默认主键做分批,但这种方式可能导致重复处理或遗漏记录。Rails 5+修复了这个潜在问题,所以现在会严格校验主键是否在select结果中。
内容的提问来源于stack exchange,提问作者Snips
相关产品推荐
相关产品推荐

