【问题标题】:SQL query checking columns in first table or looking up rows in second tableSQL 查询检查第一个表中的列或查找第二个表中的行
【发布时间】:2015-06-03 14:12:38
【问题描述】:

所以我有以下情况:

我有一个帖子模型,它总是有 2 或 4 个参数

class Post < ActiveRecord::Base
  # has two columns, status and published (boolean)
  has_many :arguments
end

和一个参数模型

class Argument < ActiveRecord::Base
  # has moderated column (boolean) and text
  belongs_to :post
end

我想知道我是否可以编写一个查询来获取具有以下条件的帖子:

1) 帖子有未经审核的参数,其中第一个按 id 排序(未更新_at)属于具有 id = 5 的用户(例如)

-------- 或 ------

2) 帖子status = 1 and published = true

PS.:我正在使用 PostgreSQL。

【问题讨论】:

    标签: sql ruby-on-rails postgresql greatest-n-per-group


    【解决方案1】:

    翻译成SQL:

    SELECT p.*
    FROM   posts p
    LEFT   JOIN (
       SELECT DISTINCT ON (post_id)
              post_id, user_id
       FROM   arguments
       WHERE  moderated = FALSE
       ORDER  BY post_id, id
       ) a ON a.post_id = p.id AND a.user_id = 5
    WHERE  a.post_id IS NOT NULL OR        -- condition 1
          (a.status = 1 and a.published);  -- condition 2
    

    DISTINCT ON的详细信息:

    为什么是LEFT JOIN?

    如果只有条件1),我们可以简化:

    SELECT p.*
    FROM   posts p
    JOIN  (
       SELECT DISTINCT ...
       ) a ON a.post_id = p.id AND a.user_id = 5;
    

    但是您添加了替代(不是附加)条件2)。如果我们使用普通的[INNER] JOIN,则未通过条件1) 的帖子将立即从选择中删除,并且永远不会获得第二次机会。我添加了多余的括号(operator precedence 可以在没有括号的情况下为我们工作)和换行符指出这是“另一种方式”:

    (a.status = 1 and a.published)
    

    当然,我们现在必须添加条件检查1):

    a.post_id IS NOT NULL
    

    这可以在不重复行的情况下工作,因为子查询在每个帖子中返回正好 1 或 0 行(而不是更多)。

    这是一种解决它的方法。对于每个帖子只有少数属性(2 - 4)和非平凡数量的合格属性来说,应该是一个很好的选择。根据您的实际数据分布,可能还有其他更快的查询技术:

    【讨论】:

    • 我对其进行了一些更改,经过一些测试后,我成功了 :) 非常感谢您的时间和帮助,对于一个糟糕的书面问题,我深表歉意。我唯一要指出的是,我需要使用复数形式的表名称,例如“FROM posts p”,并且与参数表相同
    • @JustMichael:这似乎是 Ruby 命名约定。就个人而言,我更喜欢表格的单数术语。复数只添加更长的名称。 (我也不会像某些 ORM 那样使用非描述性的 id 作为列名。)
    • 是的,这是一个 Rails 约定,感谢您的解释
    • 它按预期工作,但我想再问一件事,我读过一些信息说即使右连接为空,左连接也会返回左记录,所以我想知道这个查询是否可以返回帖子没有加入的论点?或者我错过了什么?
    • @JustMichael:你听说的LEFT JOIN 是完全正确的。我添加了一个理由。
    猜你喜欢
    • 2021-08-23
    • 2012-08-18
    • 1970-01-01
    • 2020-05-17
    • 2020-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-02
    相关资源
    最近更新 更多