重构 postgres join vs except

refactoring postgres join vs except

我正在尝试重构我的一个查询,但我做的事情并不正确。

我想合并两个查询并创建一个,但我对它如何与 LEFT JOIN 一起工作感到困惑。

All QuizMasters who have a state of "active"

减号(-)

QuizMasters who have an "active" event on a given day (not all QuizMasters have events only ~25%).

定义

  • Events store start_at dow/wday for a given event, eg Monday-Sunday (albeit as a DateTime, only the wday and time are relevant).
  • Events and QuizMasters have states which are either "active" or not.

旧查询(哪个数据正确)

SELECT first_name, last_name, email
FROM quiz_masters
WHERE quiz_masters.state = 'active' # (175 rows)

EXCEPT

SELECT first_name, last_name, email
FROM quiz_masters
LEFT JOIN events ON events.quiz_master_id = quiz_masters.id
WHERE quiz_masters.state = 'active'
AND EXTRACT(dow FROM events.start_at::timestamp::date) = 3 AND events.state = 'active'
GROUP BY first_name, last_name, email # (- 20 rows)

共有 155 行匹配查询。

组合查询无效

我想将它们组合成类似的东西:

SELECT first_name, last_name, email
FROM quiz_masters
LEFT JOIN events ON events.quiz_master_id = quiz_masters.id
WHERE quiz_masters.state = 'active'
AND events.quiz_master_id IS null
OR (EXTRACT(dow FROM events.start_at::timestamp::date) <> 3 AND events.state = 'active')
GROUP BY first_name, last_name, email

144 行(缺少 11 行)

但我不确定如何保留一些 quiz_masters 活跃但没有任何事件的所有行。它仍然删除它们。也许我需要其他类型的加入?

在第一个查询中,您排除了周三的所有活动事件,因此包括了任何一天的非活动事件。在组合查询中,您包括除星期三以外的任何一天都活跃的所有事件,并且没有任何非活跃事件。那是你的 11 行差异。

这应该让您回到 155 行:

SELECT DISTINCT first_name, last_name, email
FROM quiz_masters
LEFT JOIN (
    SELECT quiz_master_id AS id, state
    FROM events
    WHERE EXTRACT(dow FROM events.start_at::timestamp) = 3
    AND events.state = 'active') ev USING (id)
WHERE quiz_masters.state = 'active'
AND ev.state IS NULL;

显然您的测验大师有多个条目,但与其做 GROUP BY,不如做 select DISTINCT 行。 GROUP BY 只能与聚合函数一起使用。

使用人类语言。

第一次查询:

Remove from quiz_masters all entries who have the active events at the dow = 3

第二次查询:

Select entries from quiz_masters who have active events at the dow <> 3

总的来说,没有平等的条件。例如,如果 quiz_masters 在 dow = 3 和 dow = 4 同时有活动事件,那么它将在第一个查询中不存在,但在第二个查询中出现。另一个例子:quiz_masters 根本没有事件。然后它将出现在第一个查询中,而在第二个查询中不存在。

大多数情况下,这种不便是因为 left (outer) 联接的错误用法:在 where 子句中使用左联接 table 将其转换为 (inner)加入。如果 left join 正常工作 - 第一个查询将为空,第二个查询将 return 来自 quiz_masters 的所有活动条目独立于事件顺便说一句。