如果可以安全地假设连接表中没有未分配给游戏的问题的行,则:
t = Question.where("not exists (select null from games_questions gq where gq.question_id = questions.id)").count
如果您需要实际的问题对象,那么当然可以省略计数。
您的查询将类似于:
select count(*)
from questions
where not exists (
select null
from games_questions gq
where gq.question_id = questions.id);
它计算问题表中没有从相关子查询返回的行的所有行(因此,在相关子查询的 select 子句中放置什么并不重要,我通常使用 NULL)。
因此,对于 id = 5 的问题,只有在 games_questions 表中找不到 question_id = 5 的行时才会返回该行。
尽管幼稚的查询优化器可能将其实现为对问题的全表扫描并为每一行执行子查询,但更复杂的优化器会将其识别为反连接并更有效地实现。在 Oracle 中,它可能是哈希反连接,尽管这取决于每个表中的行数。如果问题有 10 行,games_questions 有 1,000,000 行,并且 games_questions.question_id 被索引,您可能会看到更简单的执行计划,它使用嵌套循环来探测问题中每一行的 games_questions 表。