如何在Rails中将多个SQL查询合并成单个查询?

3

在我的rails代码中,我需要根据记录的日期和记录所接收到的投票组合来查询表格。我在rails中通过以下方式实现:

if params[:sort_by] == "default"
    objs1 = class_name.where("created_at between '#{Date.today - 7}' and '#{Date.today}' and net_votes > 0").order("net_votes DESC")
    objs2 = class_name.where("created_at between '#{Date.today - 30}' and '#{Date.today - 7}' and net_votes > 0").order("net_votes DESC")
    objs3 = class_name.where("created_at between '#{Date.today - 90}' and '#{Date.today - 30}' and net_votes > 0").order("net_votes DESC")
    objs4 = class_name.where("created_at < '#{Date.today - 90}' and net_votes > 0").order("net_votes DESC")
    objs = objs1 + objs2 + objs3 + objs4

除了效率之外,我无法在组合查询结果上使用分页功能,更不用说代码非常丑陋了。应该如何正确处理呢?

提前感谢。

2个回答

4

使用order而不是where来进行排序逻辑:

order_by_sql = <<-SQL
CASE WHEN created_at between '#{Date.today - 7}' and '#{Date.today}' THEN 1
     WHEN created_at between '#{Date.today - 30}' and '#{Date.today - 7}' THEN 2
     WHEN created_at between '#{Date.today - 90}' and '#{Date.today - 30}' THEN 3
     ELSE 4
END
SQL

objs = class_name.where('net_votes > 0').order(order_by_sql)

太棒了,这使得查询性能提高了50%。谢谢。 - Daniel Kim

0

有几件事情可以让这个程序更加优雅和高效:

1)将每个条件封装到一个作用域中。例如,net_vtoes > 0 是可重复使用的:

def self.has_votes
  where("net_votes > 0")
end

def self.ordered 
  order("net_votes DESC")
end

def self.last_week
  where("created_at between '#{Date.today - 7}' and '#{Date.today}'")
end

2) 根据 Ryan Bates 在 RailsCast 中的建议,创建一个作用域运算符,以允许您以 OR 方式组合 where 条件: http://railscasts.com/episodes/355-hacking-with-arel?view=asciicast。然后,您可以构建如下语句:

(MyClass.last_week | MyClass.last_month).has_votes.ordered

由于您直到查询构建后才实例化模型,因此这不会产生所需的排序顺序... - PinnyM
为什么?ordered是一个活动记录作用域,而|是一种新的运算符,它将作用域与SQL OR语句相结合。也许你把它和标准的数组并集运算符混淆了? - steakchaser
是的,但是有序范围并不强制执行所需的相同顺序。 OP的代码导致记录按创建时间排序,先是过去一周,然后是过去一个月,然后是90天,最后是其他所有内容。您的范围仅通过投票计数对它们进行了排序(不确定您从哪里获取了该信息)。 - PinnyM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接