1

我正在编写一个 Rails 应用程序,用户可以在其中使用问题数据库测试自己。我有用户和问题表。当一个问题被回答时,一个 QuestionAttempt 对象被创建,链接到用户和问题,它有一个布尔属性“正确”,存储用户是否得到了正确的问题。

我想允许用户使用以下选项搜索问题:

  1. 显示我以前没有尝试过的问题(即此问题/用户不存在 QuestionAttempt 对象)
  2. 显示我以前没有回答过的问题(即此问题/用户不存在 QuestionAttempt 对象,正确 == true)

鉴于数据库很大,我需要相当有效的查询来做到这一点。我已经使用以下代码成功实现了这些查询中的第一个:

Question.joins("LEFT OUTER JOIN question_attempts ON question_attempts.question_id = questions.id").where("question_attempts.id IS NULL AND question_attempts.user_id = #{user_id}")

这将返回给定用户没有 QuestionAttempt 模型的所有问题。但是我无法为我的第二个问题找出必要的查询,找到所有没有正确 == true 的 QuestionAttempt 模型的问题。我尝试了以下方法:

Question.joins("LEFT OUTER JOIN question_attempts ON question_attempts.question_id = questions.id").where("question_attempts.user_id = #{user_id} AND (question_attempts.correct = 0 OR question_attempts.id IS NULL)")

这会选择尚未尝试或回答错误的问题。然而,问题可能已被多次尝试,有一些正确和一些不正确的答案——我不想返回这些问题,只要它们至少有一次正确的尝试。如何从该查询中排除这些问题?

非常感谢

4

2 回答 2

1

好吧,我想您可以使用预选来获取所有未正确回答的问题。
你应该试试

question_ids = Question.includes(:question_attempts).where("question_attempts.correct = 1 and questions_attempts.user_id = #{user_id}").pluck(:id) 
Question.joins("LEFT OUTER JOIN question_attempts ON question_attempts.question_id = questions.id").where("question_attempts.user_id = #{user_id} AND (question_attempts.id IS NULL OR question.id NOT IN (#{question_ids}))")
于 2013-06-17T19:18:59.203 回答
1

我相信你应该尝试强制 Rails 变成不同的形状以获得良好的数据库查询的程度是有限的,因为最合适的 SQL 语法是:

select ...
from   questions
where  not exists (
         select null
         from   question_attempts
         where  question_attempts.question_id = questions.id and
                question_attempts.user_id     = #{user_id}   and
                question_attempts.correct     = 0)

或者换一种说法,“列出该用户没有正确答案记录的问题。”。

因此我会简单地写:

Question.where("not exists (
                  select null
                  from   question_attempts
                  where  question_attempts.question_id = questions.id and
                         question_attempts.user_id     = #{user_id}   and
                         question_attempts.correct     = 0)")

这可以写成一个连接,但是一个像样的 RDBMS 查询优化器无论如何都会将一个不存在转换为一个反连接,我认为这种语法更自然。

于 2013-06-17T19:28:36.393 回答