2014-11-22 67 views
0

我有一個使用postgres的Rails 4項目的半複雜查詢。我想看看是否有可能將查詢轉換爲ActiveRecord/Arel,並且如果Rails約定在需要執行原始SQL時使用ActiveRecord::Base.connection.execute(sql)「Rails方式」來執行一個seml複雜的查詢

這裏有一個查詢我要執行:

select 
    sum(case when is_graded = true then 1 else 0 end) graded, 
    sum(case when is_canceled = true then 1 else 0 end) canceled, 
    sum(case when is_graded IS NULL and is_canceled IS NULL then 1 else 0 end) in_progress 
from exams 
where user_id = 1 and quiz_id = 114; 

我想要的結果,格式爲:

{"graded"=>"2", "canceled"=>"2", "in_progress"=>"1"} 

這得到我,我要找的答案,但似乎醜陋我想看看有沒有更好的辦法:

sql="select 
    sum(case when is_graded = true then 1 else 0 end) graded, 
    sum(case when is_canceled = true then 1 else 0 end) canceled, 
    sum(case when is_graded IS NULL and is_canceled IS NULL then 1 else 0 end) in_progress 
from exams 
where user_id = 1 and quiz_id = 114;" 

result = ActiveRecord::Base.connection.execute(sql) 

result.to_a.first 

我的問題重述:

  1. 是否可以使用Arel/ActiveRecord編寫此查詢?如果是這樣,怎麼樣?

  2. 如果您需要在Rails中執行原始SQL,是否使用「Rails約定」ActiveRecord::Base.connection.execute(sql)This answer表示最好在複雜的情況下直接運行SQL,this answer是我發現的地方ActiveRecord::Base.connection.execute(sql)

回答

1

大概要經過ActiveRecord的將是這樣的最簡單的方法:

Exam.where(:user_id => 1, :quiz_id => 114).select(%q{ 
    sum(case when is_graded then 1 else 0 end) graded, 
    sum(case when is_canceled then 1 else 0 end) canceled, 
    sum(case when is_graded IS NULL and is_canceled IS NULL then 1 else 0 end) in_progress 
})[0] 

這會給你一個Exam比如在result,但是這不會是一個正常的Examidis_graded ,...屬性,這個屬性將具有graded,canceledin_progress屬性。您會看到,當您說select('...')時,AR將生成屬性與SELECT子句中的命名列相匹配的對象。

然後到attributes方法的調用應該給你的哈希:

result = Exam.where(:user_id => 1, :quiz_id => 114).select(%q{...})[0].attributes 
# result is now like {"graded"=>"2", "canceled"=>"2", "in_progress"=>"1"} 

你也許可以表達對AREL方法的SUM和CASE表達式,但它會是一個又大又醜的混亂,所以我不會理會。

+1

我使用'[0]'代替'first',因爲'Exam.where'返回了一個ActiveRecord關係對象,並且正在將'first'解釋爲查詢的一部分並添加了'ORDER BY'。謝謝你的出色答案。 – Powers 2014-11-24 13:33:08

+0

感謝您指出「第一」與「[0]」的東西。這可能與版本有關,AR檢查時添加了「LIMIT 1」,但沒有「ORDER BY」,結果相同。無論如何,爲了安全起見,我將它切換到了「[0]」。 – 2014-11-24 17:38:47