我的模型结构如下:
我需要一个rails查询来查找:
有多少用户在与答案相对应的给定调查的最后一次ResponseSet(意味着最后一次尝试)中选择了给定答案。
有多少用户在针对与问题对应的给定调查的最后一个ResponseSet(意味着最后一次尝试)中选择了一个给定问题。
答案 0 :(得分:2)
由于您使用的是PostgreSQL,我建议在子查询中使用窗口函数来简化逻辑。子查询将收集给定查询的所有response_sets。外部查询过滤到该调查的每个用户的最后一个ResponseSet(基于窗口函数生成的rowNum),并确保它包含与给定答案关联的响应:
select_sql <<-SELECT
response_sets.*,
ROW_NUMBER() OVER (PARTITION BY response_sets.user_id ORDER BY response_sets.id DESC) as rowNum
SELECT
subquery = survey.response_sets.select(select_sql).to_sql
ResponseSet.joins(:responses).from(Arel.sql("(#{subquery}) response_sets")).
where(responses: {answer_id: answer.id}).
where("rowNum = 1").count
请注意,这假设给定的答案每个ResponseSet只能使用一次。如果不是这种情况,您可以将.count
替换为.count(:distinct => :user_id)
答案 1 :(得分:1)
正如我在评论中提到的,你需要一个子查询或Postgresql WITH
子句来查找最新的响应,如果有很多ReponseSet,即使使用索引也会非常昂贵。
另一方面,如果您的表只包含最新的响应,那么将提供简单的嵌套连接。如果我正确理解您的架构,那么这些都很接近:
User.count(:joins => { :survey => {:latest_response_set => { :response => :answer }}},
:conditions => ['answers.id = ?', answer_id])
User.count(:joins => { :survey => {:latest_response_set => { :response => :question}}},
:conditions => ['questions.id = ? and surveys.id = ?', question_id, survey_id])
您可以使用after_save
回调更新最新的响应表。这是相对安全的,因为回调包含在事务中。