sql - 查找不存在连接的记录

标签 sql ruby-on-rails postgresql

我有一个范围可以根据用户是否对它们投票来限制所有问题。在模型中:

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() (Ⓘ) 之间是双重的:

  1. 性能

    Ⓔ 通常更快。一旦找到第一个匹配项,它就会停止处理子查询。 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 处理会使其更加复杂。

  2. 正确性

    如果子查询表达式中的结果值之一是 NULL,则 Ⓘ 的结果是 NULL,而普通逻辑会期望 TRUE - 和 Ⓔ 将返回 TRUEThe 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 EXISTSNOT IN 之外,还有其他语法选项,包括 LEFT JOIN/IS NULLEXCEPT .见:

关于sql - 查找不存在连接的记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14251180/

相关文章:

PostgreSQL:如何修改/复制之前的文本

mysql - CURRENT_TIMESTAMP 与服务器上的当前时间不匹配

mysql - 如何进行表连接,其中组合键是访问号码和日期 +/- 1 天

ruby-on-rails - 为什么我的 Rails 无法在现有项目/存储库的新开发环境上运行?

ruby-on-rails - 以嵌套形式获取当前对象

ruby-on-rails-3 - 如何在 Heroku 上使用 hstore

database - 在模式中对 postgresql 表进行分组

SQL 显示 |从今天开始选择数据 |仅限当天

MySQL 转换为 TINYINT

javascript - 悬停父级时如何向子级 div 添加样式?