如何按expected_date降序排序后更新installment表的number字段值
实现方案
方案1:逐笔更新(适合分期数少的场景)
最直观的实现,先按expected_date降序排序,遍历的时候携带索引赋值即可,number默认从1开始计数:
@payment.installments.order(expected_date: :desc).each_with_index do |installment, index| installment.update(number: index + 1) end
如果需要保证数据一致性,建议加事务包裹,更新失败自动回滚:
ActiveRecord::Base.transaction do @payment.installments.order(expected_date: :desc).each_with_index do |installment, index| installment.update!(number: index + 1) end end
方案2:批量更新(适合分期数多的高性能场景)
逐笔更新会产生N次SQL请求,分期数较多时推荐用批量更新,全程只执行1次SQL请求,性能提升明显:
# 按排序规则拿到所有分期id sorted_installment_ids = @payment.installments.order(expected_date: :desc).pluck(:id) # 构造CASE语句匹配赋值 case_condition = sorted_installment_ids.each_with_index.map do |id, idx| "WHEN id = #{id} THEN #{idx + 1}" end.join(' ') Installment.where(id: sorted_installment_ids).update_all("number = CASE #{case_condition} ELSE number END")
优化建议
如果你的业务里经常需要按expected_date降序获取分期,可以直接在Payment模型的关联中定义默认排序,后续调用时不需要重复写排序逻辑:
# app/models/payment.rb class Payment < ApplicationRecord has_many :installments, -> { order(expected_date: :desc) } # 其他逻辑 end
内容的提问来源于stack exchange,提问作者Joana
相关产品推荐
相关产品推荐

