Да, вы можете использовать левое внешнее соединение для этого.Обычное INNER JOIN будет включать только строки, соответствующие условию соединения, LEFT JOIN будет включать в себя совпадающие строки и выделит несопоставленные строки, поместив NULL во все столбцы ( Документы PostgreSQL имеют разумное описание).
Итак, вы делаете ЛЕВОЕ СОЕДИНЕНИЕ, а затем ищите несопоставленную строку, ища NULL.SQL будет выглядеть примерно так:
select ...
from questions
left outer join user_questions on questions.id = user_questions.question_id
where user_questions.question_id is null
Это даст вам все вопросы, на которые еще нет ответа.В ActiveRecord вы можете сделать что-то вроде этого:
Question.joins('left outer join user_questions on question.id = user_questions.question_id')
.where(:user_questions => { :question_id => nil })
.limit(1)
Возможно, вы захотите поиграть и со случайным порядком, но это должно помочь вам начать.Если это не дает вам соответствия, тогда вы можете получить случайный вопрос с чем-то вроде этого:
n = Questions.count
q = Questions.offset(rand(n)).limit(1)
Вы можете сделать то же самое с Questions.order('random()').limit(1)
, но ORDER BY random()
может быть неприятно сбольшая база данных;получение счетчика должно быть довольно быстрым, поэтому случайный выбор в Ruby должен быть достаточно быстрым, и ваша база данных не будет вас ненавидеть.
Также ознакомьтесь с документами .Чтобы привести это в порядок, joins
, я работаю с базой данных с немного нестандартной структурой, поэтому иногда приходится делать что-то долгое;ActiveRecord отказывается делать ЛЕВОЕ СОЕДИНЕНИЕ для меня, если я не произнесу это, YMMV.