使用独立值更新多个记录的有效方法?

时间:2013-05-26 21:56:09

标签: sql ruby-on-rails-3 rails-activerecord

我有以下(过度数据库昂贵)方法:

    def reorder_area_routes_by_demographics!
      self.area_routes.joins(:route).order(self.demo_criteria, :proximity_rank).readonly(false).each_with_index do |area_route, i|
        area_route.update_attributes(match_rank: i)
      end
    end

但这导致每个area_route的UPDATE查询。有没有办法在一个查询中执行此操作?

- 编辑 -

最终解决方案,根据coreyward建议:

def reorder_area_routes_by_demographics!
  sorted_ids = area_routes.joins(:route).order(self.demo_criteria, :proximity_rank).pluck(:'area_routes.id')
  AreaRoute.update_all [efficient_sort_sql(sorted_ids), *sorted_ids], {id: sorted_ids}
end

def efficient_sort_sql(sorted_ids, offset=0)
  offset.upto(offset + sorted_ids.count - 1).inject('match_rank = CASE id ') do |sql, i|
    sql << "WHEN ? THEN #{id} "
  end << 'END'
end

1 个答案:

答案 0 :(得分:1)

我使用以下内容执行类似的任务:根据params中的顺序更新一组记录的排序位置。您可能需要以不同的方式重构或合并以适应您正在应用的范围,但我认为这会向您发送正确的方向。

def efficient_sort_sql(sortable_ids, offset = 1)
  offset.upto(offset + sortable_ids.count - 1).reduce('position = CASE id ') do |sql, i|
    sql << "WHEN ? THEN #{i} "
  end << 'END'
end

Model.update_all [efficient_sort_sql(sortable_ids, offset), *sortable_ids], { id: sortable_ids }

sortable_ids是一个表示每个对象的id的整数数组。生成的SQL看起来像这样:

UPDATE pancakes SET position = CASE id WHEN 5 THEN 1 WHEN 3 THEN 2 WHEN 4 THEN 3 WHEN 1 THEN 4 WHEN 2 THEN 5 WHERE id IN (5,3,4,1,2);

这就是,除了丑陋之外,一个性能相当高的查询和(至少在Postgresql中)将完全成功或完全失败。