通过比较总-vs指定的状态

时间:2017-01-19 19:38:46

标签: mysql sql innodb

我有一个客户列表。每个客户端可以有多个活动(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
);

我该如何改进?

感谢您的帮助。

3 个答案:

答案 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)