2014-01-10 155 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