我有一个范围可以根据用户是否对它们投票来限制所有问题
。在模型中:
scope :answered_by, lambda {|u| joins(:votes).where("votes.user_id = ?", u.id) }
scope :unanswered_by, lambda {|u| joins(:votes).where("votes.user_id != ?", u.id) }
在 Controller 中,我这样调用它们:
@answered = Question.answered_by(current_user)
@unanswered = Question.unanswered_by(current_user)
unanswered_by 范围不正确。我基本上想找到没有投票的地方。相反,它试图寻找是否有不等于当前用户的投票。关于如何返回不存在连接的所有记录的任何想法?
最佳答案
使用 EXISTS
表达式:
WHERE NOT EXISTS (
SELECT FROM votes v -- SELECT list can be empty
WHERE v.some_id = base_table.some_id
AND v.user_id = ?
)
区别
... NOT EXISTS()
(Ⓔ) 和 NOT IN()
(Ⓘ) 之间是双重的:
性能
Ⓔ 通常更快。一旦找到第一个匹配项,它就会停止处理子查询。 The manual:
The subquery will generally only be executed long enough to determine whether at least one row is returned, not all the way to completion.
Ⓘ 也可以通过查询规划器进行优化,但程度较小,因为
NULL
处理会使其更加复杂。正确性
如果子查询表达式中的结果值之一是
NULL
,则 Ⓘ 的结果是NULL
,而普通逻辑会期望TRUE
- 和 Ⓔ 将返回TRUE
。 The manual:If all the per-row results are either unequal or null, with at least one null, then the result of
NOT IN
is null.
本质上,(NOT) EXISTS
在大多数情况下是更好的选择。
例子
您的查询可以如下所示:
SELECT *
FROM questions q
WHERE NOT EXISTS (
SELECT FROM votes v
WHERE v.question_id = q.id
AND v.user_id = ?
);
不要加入基本查询中的votes
。这将使努力付之东流。
除了 NOT EXISTS
和 NOT IN
之外,还有其他语法选项,包括 LEFT JOIN/IS NULL
和 EXCEPT
.见:
关于sql - 查找不存在连接的记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14251180/