我有一个客户列表。每个客户端可以有多个活动(0 .. *)。每个活动都包含一个状态“is_completed”,它是一个布尔值(True / False)。
我需要检索已完成所有活动的客户列表:
我编写了一个SQL查询来完成这项工作,但我不相信它已经过优化:
SELECT DISTINCT cc.client_id
FROM clients_clientactivity AS cc
LEFT JOIN clients_client AS c ON (c.id = cc.client_id)
WHERE c.client_type_id = 2
AND (
SELECT COUNT(cc1.id) FROM clients_clientactivity AS cc1 WHERE cc1.client_id = cc.client_id
) = (
SELECT COUNT(cc2.id) FROM clients_clientactivity AS cc2 WHERE cc2.is_completed = True AND cc2.client_id = cc.client_id
);
我该如何改进?
感谢您的帮助。
答案 0 :(得分:1)
你可以使用not in select for not true
SELECT DISTINCT cc.client_id
FROM clients_clientactivity AS cc
LEFT JOIN clients_client AS c ON (c.id = cc.client_id)
WHERE c.client_type_id = 2
AND cc.client_id NOT IN (
SELECT cc2.client_id
FROM clients_clientactivity AS cc2
WHERE cc2.is_completed != True
)
答案 1 :(得分:1)
我会使用聚合和SELECT c.id
FROM clients_clientactivity ca JOIN
clients_client c
ON c.id = ca.client_id
WHERE c.client_type_id = 2
GROUP BY c.id
HAVING COUNT(*) = SUM(ca.iscompleted)
:
WHERE
您的LEFT JOIN
子句会将INNER JOIN
转换为LEFT JOIN
,因此我删除了{{1}}。
答案 2 :(得分:0)
让我们进一步简化:
SELECT client_id
FROM clients_clientactivity
WHERE MIN(is_completed) = TRUE
GROUP BY client_id
(TRUE == 1,FALSE == 0)
子查询通常很慢。 NOT IN ( SELECT ... )
非常糟糕(除非优化器神奇地变得更聪明)。
您没有解释client_type_id = 2
的方式,但可能类似于:
clients_client
SELECT a.client_id
FROM clients_client AS c
JOIN clients_clientactivity AS a ON (c.id = a.client_id)
WHERE MIN(a.is_completed) = TRUE
AND c.client_type_id = 2
GROUP BY a.client_id
如果表现有问题,那么:
c
需要INDEX(client_type_id, id)
a
需要INDEX(client_id, is_completed)