对关联中存在的元素进行排序,其中第一个元素将是最多选定关联中存在的元素。 换句话说,大多数订单中的订单元素存在于给定列表中。 这听起来很复杂,所以这里是工作示例,但速度超慢。
我们想对汽车进行分类,大多数司机都可以驾驶它们
complex
装载大约需要1秒,只有20辆车。 但现在我们有100辆汽车的情况,计算它需要几十年的时间。
我们如何编写sql请求来订购? 它不起作用,但显示了一些逻辑:
# we have some ids of driver seleted by user
dynamic_drivers_ids = [1,2,3,100,5]
@cars = Car.all.includes(:driving_levels)
@cars.sort_by {|e| (e.driving_level.map(&:driver_id) & dynamic_drivers_ids ).size * -1 }
Db表格如下:
Car.includes(:driving_levels).order("driving_level.id IN = ? AND driving_level.size", dynamic_drivers_ids)
答案 0 :(得分:0)
左连接driving_levels
怎么样,但只有那些在driver_id
中有dynamic_drivers_ids
的人(希望dynamic_drivers_ids
不是来自用户,否则它是sql-injection-prone) )?然后你可以按照驾驶级别的计数进行分组和排序吗?
看起来像这样:
Car
.joins("LEFT OUTER JOIN driving_levels ON
driving_levels.id = cars.driving_level_id AND
driving_level.driver_id IN (#{dynamic_drivers_ids})")
.group(:id).order("COUNT(driving_levels.id)")
答案 1 :(得分:0)
首先,您应该在这里使用where
和references
:
dynamic_drivers_ids = [1,2,3,100,5]
@cars = Car.includes(:driving_level).
references(:driving_level).
where(driving_level: {id: dynamic_drivers_ids})
这里会发生什么,它会加入表cars
和driving_level
,并且只提取driving_level
条记录,这些记录包含这些ID(您不必这样做:e.driving_level.map(&:driver_id) & dynamic_drivers_ids
) 。你不会再删除所有driving_level
条记录了。
这应该会大大加快。
中学:按协会排序。最简单的方法是使用列来计算我们的关联,然后对它进行排序:
@cars = Car.select('COUNT(driving_levels.id) as driving_levels_size').
includes(:driving_level).
references(:driving_level).
where(driving_level: {id: dynamic_drivers_ids}).
group('cars.id, driving_levels.id').
order('driving_levels_size')
这应该返回正确的顺序和正确的关联记录。
答案 2 :(得分:0)
如果driving_levels
包含driver_id
1,2,3,100,5。
select_clause = <<~SQL
cars.*,
( SELECT count(DISTINCT driver_id) FROM driving_levels
WHERE driver_id IN (1,2,3,100,5)
OR car_id=cars.id ) as driver_cnt
SQL
Car
.select(select_clause)
.order('driver_cnt DESC')
.to_a