计数,分组依据,子查询,左加入不按预期工作

时间:2015-02-25 01:33:05

标签: mysql

令我感到困惑的是,谷歌没有多少帮助我,希望有人能指出我正确的方向。

请注意,为了简化问题,我省略了表中与问题无关的一些字段。

联系人

contact_id
name
email

contact_uuids

uuid
contact_id

visitor_activity

uuid
event

contact_communications

comm_id
contact_id
employee_id

查询

SELECT 
  `c`.*,
  (SELECT COUNT(`log_id`) FROM `contact_communications` `cc`        WHERE `cc`.`contact_id` = `c`.`contact_id`) as `num_comms`,
  (SELECT MAX(`date`)   FROM `contact_communications` `cc`      WHERE `cc`.`contact_id` = `c`.`contact_id`) as `latest_date`,
  (SELECT MIN(`date`)   FROM `contact_communications` `cc`      WHERE `cc`.`contact_id` = `c`.`contact_id`) as `first_date`,
  (SELECT COUNT(`vaid`)     FROM `visitor_activity` `va`            WHERE `va`.`uuid`       = `cu`.`uuid`)      as `num_act`
FROM `contacts` `c`
LEFT JOIN `contact_uuids` `cu` ON `c`.`contact_id` = `cu`.`contact_id`
GROUP BY `c`.`contact_id`
ORDER BY `c`.`name` ASC

某些联系人有多个UUID(超过20或30)。

当我执行不带GROUP BY语句的查询时,我得到了我期望的结果 - 为该联系人存在的每个UUID返回一行,并使用正确的“num_comms”和“num_act”数字。

但是当我添加GROUP BY语句时,“num_comms”比预期的要小很多,“num_act”只返回没有GROUP BY语句的第一行的值。

我尝试在子查询中执行“WHERE NOT IN”,但这只会使服务器崩溃,因为它太强烈了。

那么 - 如何让这个从LEFT JOIN中添加所有COUNT值而不只是返回第一个值?

此外,如果有人可以帮助我优化这一点,那就太棒了。

1 个答案:

答案 0 :(得分:1)

两个问题:

  • GROUP BY ccontact_id不包含所有非汇总列。这是一个MySQL扩展。你得到的是除contact_id

  • 以外的行的随机值
  • JOIN增加了混乱。您对visitor_activity的唯一用途是COUNT(*)。但这没有意义,因为它仅限于一个UUID,而行仅限于一个contact_id。重新考虑其目的。

删除此行:

  (SELECT COUNT(`vaid`) FROM `visitor_activity` `va` WHERE `va`.`uuid`       = `cu`.`uuid`) as `num_act`

其余的可以正常工作。

我将继续假设您希望与一个contact_id关联的所有uuids都包含visitor_activity中所有行的COUNT。

看看是否:

( SELECT  COUNT(*)
    FROM  `contacts` c2
    JOIN  `visitor_activity` USING(uuid)
    WHERE  c2.contact_id = c.contact_id as `num_act` ) AS  num_act

将适用于最后一个子查询。同时,删除JOIN:

LEFT JOIN `contact_uuids` `cu` ON `c`.`contact_id` = `cu`.`contact_id`

现在,回到另一个问题(GROUP BY的非标准用法)。假设contact_id是PRIMARY KEY,那么只需删除

即可
GROUP BY `c`.`contact_id`