我试图重构我的一个查询,而我却没有做正确的事情。
我想结合两个查询并制作一个,但我对它如何与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
行的所有行。它仍然会删除它们。也许我需要其他一些加入?
答案 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
行,而不是DISTINCT
。 GROUP 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返回所有活动条目。