如果没有连接/子查询:
即,如果您只检索前 10 个(只有少数)网站,而不是数千条website记录,或者您不会在数千个数组中迭代每一个。
ratings = Rating.where(
created_at: Time.parse('2019-01-01')..Time.parse('2019-06-01')
).group(
:website_id
).order(
'sum(score) desc'
).select(
:website_id
)
top_10_winner_websites = ratings.take(10).map(&:website)
# above is ordered by sum(score) desc
# so,
# top_10_winner_websites[0] has the highest sum score, while
# top_10_winner_websites[-1] has the lowest sum score amongst the 10
注意:请注意,上面的查询只是“选择” ratings.website_id,而不是ratings.*意味着对象的其他属性(如id和score)ratings都是 all nil,只有除了website_id
如果有连接/子查询:
编辑:下面的 TODO 还没有完全工作;可能需要帮助。无法找到/解决保留website_id子查询外部排序的方法。这段时间很忙。
如果您要迭代每条website记录,或者要检索数千website条记录,以防止 N+1 查询。
top_10_winner_websites = Website.where(
id: Rating.where(
created_at: Time.parse('2019-01-01')..Time.parse('2019-06-01')
).group(
:website_id
).order(
'sum(ratings.score) desc'
).select(
'website_id r'
)
).limit(10).order('r.website_id asc')
当前解决方法(对于上面未完成的子查询):
作为解决子查询外部“保留排序”的解决方法,同时防止 N+1 查询:
ratings = Rating.where(
created_at: Time.parse('2019-01-01')..Time.parse('2019-06-01')
).group(
:website_id
).order(
'sum(ratings.score) desc'
).select(
:website_id
)
top_10_winner_website_ids = ratings.take(10).map(&:website_id)
top_10_winner_websites = Website.where(
id: top_10_winner_website_ids
).sort_by do |website|
top_10_winner_website_ids.index(website.id)
end
编辑:根据扩展请求,您可以检查并获取网站的排名:
website_to_check = Website.find(1)
index = top_10_winner_websites.index{|winner_website| winner_website.id == website_to_check.id }
if index.nil?
puts 'Website was not part of the top 10 winners in this time period'
else
puts "Website rank for this time period was: #{index + 1}"
end
^ 如果您想要一个纯 SQL 排名检查器,我不太确定如何实现它。
编辑:根据扩展请求为Website记录提供额外的“条件”:
...您仍然可以使用joins(:website),但这并不能阻止 N+1 查询,eager_load(:website)或者includes(:website)由于 a ,急切加载似乎不起作用PG::GroupingError,但是您仍然可以使用上述解决方法阻止 N+1 查询。请参阅下面的完整示例:
ratings = Rating.joins(:website).where(
created_at: Time.parse('2019-01-01')..Time.parse('2019-06-01'),
websites: {
some_website_attribute_1: true, # UPDATE THIS
some_website_attribute_2: 'foobar' # UPDATE THIS
}
).group(
:website_id
).order(
'sum(ratings.score) desc'
).select(
:website_id
)
top_10_winner_website_ids = ratings.take(10).map(&:website_id)
top_10_winner_websites = Website.where(
id: top_10_winner_website_ids
).sort_by do |website|
top_10_winner_website_ids.index(website.id)
end