SQL 在第一个 table 中查询检查列或在第二个 table 中查找行

SQL query checking columns in first table or looking up rows in second table

所以我有以下情况:

我有一个 post 模型,它总是有 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

我想知道我是否可以编写一个查询来获取 posts 并满足以下条件:

1) post 有未经审核的参数,其中第一个按 ID 排序(不是 updated_at)属于 id = 5 的用户(例如)

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

2) post status = 1 and published = true

PS.: 我正在使用 PostgreSQL。

翻译成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 的详细信息:

  • Select first row in each GROUP BY group?

为什么 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,post 未通过条件 1) 将立即从选择中删除,并且永远不会有第二次机会。我添加了多余的括号(operator precedence 可以在没有括号的情况下为我们工作)和一个换行符以指出这是 "the other way in":

(a.status = 1 and a.published)

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

a.post_id IS NOT NULL

这可以在不复制行的情况下工作,因为子查询 returns 每个 post(而不是更多)恰好 1 或 0 行。

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

  • Optimize GROUP BY query to retrieve latest record per user