重构postgres加入vs除了

时间:2016-08-26 09:31:59

标签: sql postgresql left-join postgresql-9.4

我试图重构我的一个查询,而我却没有做正确的事情。

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

  

状态为"活跃"

的所有QuizMaster

减号( - )

  

具有"活跃"的测验大师某一天的事件(并非所有QuizMaster都只有25%的事件)。

解释

  
      
  • 事件为特定事件存储start_at dow / wday,例如周一至周日(尽管是DateTime,只有wday和时间相关)。
  •   
  • 活动 QuizMasters 的状态为"有效"
  •   

旧查询(哪个数据正确)

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行的所有行。它仍然会删除它们。也许我需要其他一些加入?

2 个答案:

答案 0 :(得分:2)

在第一个查询中,您排除了周三活动的所有事件,因此包含了任何一天的非活动事件。在合并查询中,您包括在任何一天但周三都处于活动状态的所有事件,并且不包含任何非活动事件。这是你的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行,而不是DISTINCTGROUP BY只应与聚合函数一起使用。

答案 1 :(得分:1)

使用人类语言。

首先查询:

  

quiz_masters中删除dow = 3

处有活动事件的所有条目

第二次查询:

  

quiz_masters

中有活动事件的dow <> 3选择条目

一般情况不一样。例如,如果quiz_masters同时在dow = 3和dow = 4处有活动事件,那么它将在第一个查询中不存在但在第二个查询中存在。又一个例子:quiz_masters根本没有事件。然后它将出现在第一个中并且在第二个查询中不存在。

大多数情况下,这种不便是因为left (outer)联接的错误用法:使用where子句中的左连接表将其转换为(inner)联接。如果left join正常工作 - 第一个查询将为空,第二个将在事件BTW上独立地从quiz_masters返回所有活动条目。