2014-01-10 156 views
3

在我的rails代码中,我需要根据记录的日期和记录收到的投票的组合来对表进行查询。我完成它就像在轨道下面:如何将多个Rails SQL查询合并到一个单独的查询中?

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 

效率不谈,我不能在组合查询结果使用分页更不用说代码是非常难看。什么是正确的方法来做到这一点?

在此先感谢。

回答

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) 
+0

真棒,这导致查询50%的性能增益。谢谢 –

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贝茨在此RailsCast建议,让您可以结合其中一个或时装条件:http://railscasts.com/episodes/355-hacking-with-arel?view=asciicast。这会让你建立一个这样的陈述:

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

由于在构建查询之前您没有实例化模型,所以这不会导致所需的排序顺序... – PinnyM

+0

为什么? ordered是一个活动的记录范围,'|'是一个新的操作符,它将范围与SQL'OR'语句组合在一起。也许你把这与标准的数组联合运算符混淆? – steakchaser

+0

是的,但是有序范围并不强制按照要求排序。 OP的代码产生了在过去一周内创建的记录,然后是过去一个月,然后是90天,然后是其他一切。你的示波器只是通过投票计数来命令他们所有的人(不知道你从哪里获得)。 – PinnyM