我有一个做傻事的初始化方法.我需要将其优化为一个查询,但是我的SQL技能目前使我感到失望.我已经考虑过使用GROUP BY和UNION以及各种各样的东西,但是我只是让自己更加困惑.我将其遗赠给社区,以得出一些见解:
Class Stats
# Turn these three queries into one query that we can then
# load into the three different instance variables
def initialize(question)
# Integer = total number of answers for this question
@total = total_answers(question.id)
# Hash keyed by 0 (incorrect answers) and 1 (correct answers)
@stats_total = load_stats_total(question.id) if @total > 0
# Hash keyed by answer_id with values = total number of answers
@stats_answers = load_stats_answers(question.id) if @total > 0
end
# Returns an int = the total number of answer attempts for
# this question (right + wrong user_answers)
# Excludes anonymous users
def total_answers(question_id)
UserAnswer.count(:conditions => ['u.anonymous = 0 AND q.id = ?', question_id], :joins => 'JOIN answers a ON user_answers.answer_id = a.id JOIN questions q ON q.id = a.question_id JOIN users u ON u.id = user_answers.user_id')
end
# Returns an OrderedHash =
# {"0" => number of wrong user_answers for this question,
# "1" => number of correct user_answers for this question}
# Excludes anonymous users
def load_stats_total(question_id)
UserAnswer.count(:conditions => ['u.anonymous = 0 AND q.id = ?', question_id], :joins => 'JOIN answers a ON user_answers.answer_id = a.id JOIN questions q ON q.id = a.question_id JOIN users u ON u.id = user_answers.user_id', :group => 'a.correct')
end
# Returns an OrderedHash =
# {
# some_answer_id => total number of user_answers for this answer,
# some_other_answer_id => total number of user_answers for this answer
# ...
# }
# Excludes anonymous users
def load_stats_answers(question_id)
UserAnswer.count(:conditions => ['u.anonymous = 0 AND q.id = ?', question_id], :joins => 'JOIN answers a ON user_answers.answer_id = a.id JOIN questions q ON q.id = a.question_id JOIN users u ON u.id = user_answers.user_id', :group => 'a.id')
end
end
如果有人有任何想法,将不胜感激!
谢谢.
解决方法:
我认为您无法在一个查询中做到这一点.
至少并非没有编写纯sql.
但是,让我们尝试在ActiveRecord中找到一个不错的解决方案
首先,让我们尝试删除一些sql
UserAnswer.count(:conditions => ['u.anonymous = 0 AND q.id = ?', question_id], :joins => 'JOIN answers a ON user_answers.answer_id = a.id JOIN questions q ON q.id = a.question_id JOIN users u ON u.id = user_answers.user_id')
可以改写
UserAnswer.joins(:user).where(:users => {:anonymous => false})\
.joins(:answer => :question).where(:questions => {:id => question_id})\
.count
让我们将范围保存为魔术私有方法magic_scope
您当前的方法成为
def total_answers(question_id)
magic_scope(question_id).count
end
def load_stats_total(question_id)
magic_scope(question_id).count(:group => "answers.correct")
end
def load_stats_answers(question_id)
magic_scope(question_id).count(:group => "answers.id")
end
当然,值得注意的是,total_answers方法可以通过汇总两个load_stats_ *方法的结果得出.
如果ActiveRecord更加聪明,我们可以做
def all_the_magic(question_id)
magic_scope(question_id).count(:group => ["answers.correct", "answers.id"])
end
这样一来,我们就能获得所需的所有数据.
但据我所知,目前尚不可能.
但我希望这能使您更接近.