我在使用postgres的Rails 4项目中有一个半复杂的查询。我想知道是否可以将查询转换为ActiveRecord / Arel,如果Rails惯例是使用ActiveRecord::Base.connection.execute(sql)
,则执行原始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;
我希望结果格式为:
{"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
重申我的问题:
是否可以使用Arel / ActiveRecord编写此查询?如果是这样,怎么样?
它是" Rails惯例"如果需要在Rails中执行原始SQL,请使用ActiveRecord::Base.connection.execute(sql)
? This answer表示最好在SQL复杂时直接运行SQL,this answer是我找到ActiveRecord::Base.connection.execute(sql)
的地方。
答案 0 :(得分: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
个实例,但这不会是Exam
id
is_graded
,graded
,...属性,此属性将具有canceled
,in_progress
和select('...')
属性。你看,当你说attributes
时,AR会产生一些对象,这些对象的属性与SELECT子句中的命名列相匹配。
然后调用result = Exam.where(:user_id => 1, :quiz_id => 114).select(%q{...})[0].attributes
# result is now like {"graded"=>"2", "canceled"=>"2", "in_progress"=>"1"}
方法会给你你的哈希:
{{1}}
你可能用AREL方法表达那些SUM和CASE表达式,但这将是一个非常难看的混乱,所以我不会打扰。