MySQL Join三个表返回多个结果

时间:2015-07-01 20:46:21

标签: mysql sql select join group-by

我有三个表:我们称之为CUSTOMER,LOG和REVIEW

CUSTOMER表是:

id name
== ====
1  John
2  Jane
3  Mike

LOG表是

id customer_id  created_at
== ===========  ==========
1  1            2015-06-10
2  1            2015-06-10
3  2            2015-06-11
4  1            2015-06-13
5  2            2015-06-15
6  1            2015-06-15

REVIEW表是

id customer_id  created_at
== ===========  ==========
1  1            2015-06-10
2  2            2015-06-10
3  2            2015-06-11
4  1            2015-06-13
5  1            2015-06-15
6  1            2015-06-15
7  1            2015-06-18

我想要的是什么

CUSTOMER_ID NAME LOG_QTY REVIEW_QTY
=========== ==== ======= ==========
1           John 4       5
2           Jane 2       2
3           Mike 0       0

我得到了什么:

CUSTOMER_ID NAME LOG_QTY REVIEW_QTY
=========== ==== ======= ==========
1           John 20      20
2           Jane 4       4
3           Mike 0       0

我的查询:

                       select CUSTOMER.ID, CUSTOMER.NAME,
 count(REVIEW.CUSTOMER_ID) as REVIEW_QTY,
    count(LOG.CUSTOMER_ID) as LOG_QTY
                         from CUSTOMER
                    left join REVIEW
                           on REVIEW.CUSTOMER_ID = CUSTOMER.ID
                    left join LOG
                           on LOG.CUSTOMER_ID = CUSTOMER.ID
                     group by CUSTOMER.ID
                     order by CUSTOMER.ID

3 个答案:

答案 0 :(得分:1)

您的查询正在做的是加入评论并登录客户,两者之间没有加入条件。这意味着您正在创建每个日志的笛卡尔积,并对每个给定客户进行评估(例如,您希望约翰的4个日志乘以他的5个评论解释您获得的20个。)

解决此问题的一种方法是在子查询中单独对日志和评论执行group by

SELECT    c.id, c.name, review_qty, log_qty
FROM      customer c
LEFT JOIN (SELECT   customer_id, COUNT(*) AS review_qty
           FROM     review 
           GROUP BY customer_id) r ON r.customer_id = c.id
LEFT JOIN (SELECT   customer_id, COUNT(*) AS log_qty
           FROM     log
           GROUP BY customer_id) l ON l.customer_id = c.id
ORDER BY  c.id

答案 1 :(得分:1)

如果您在没有COUNT()GROUP BY的情况下运行查询,您会看到发生了什么:

select CUSTOMER.ID, CUSTOMER.NAME,
 REVIEW.CUSTOMER_ID as REVIEW_QTY,
 LOG.CUSTOMER_ID as LOG_QTY
from CUSTOMER
 left join REVIEW on REVIEW.CUSTOMER_ID = CUSTOMER.ID
 left join LOG on LOG.CUSTOMER_ID = CUSTOMER.ID
order by CUSTOMER.ID

这将为三个表中具有相同CUSTOMER_ID的每个可能行组合返回一行(这正是INNER JOIN所做的)。然后COUNT只计算'em!

这应该可以满足您的需求:

select CUSTOMER.ID, CUSTOMER.NAME,
 (select count(*) from REVIEW where CUSTOMER_ID = CUSTOMER.ID) as REVIEW_QTY,
 (select count(*) from LOG where CUSTOMER_ID = CUSTOMER.ID)  as LOG_QTY
from CUSTOMER
order by CUSTOMER.ID

答案 2 :(得分:1)

每当你有这样一个复杂的查询时,我总是建议你先将它分解成几块并重新组合在一起。

例如,要获取单个表的每个客户的计数,您可以使用以下聚合:

SELECT customer_id, COUNT(*) AS logCount
FROM log
GROUP BY customer_id;

您可以执行相同的审核,最后将这些结果加入到客户表中以获取其名称。您应该使用外部联接的原因是因为用户可能在其他表中没有条目。因此,您应该使用COALESCE()函数将空计数替换为0:

SELECT c.id, c.name, COALESCE(l.logCount, 0) AS logCount, COALESCE(r.reviewCount, 0) AS reviewCount
FROM customer c
LEFT JOIN(
  SELECT customer_id, COUNT(*) AS logCount
  FROM log
GROUP BY customer_id) l ON l.customer_id = c.id
LEFT JOIN(
  SELECT customer_id, COUNT(*) AS reviewCount
  FROM review
  GROUP BY customer_id) r ON r.customer_id = c.id;

以下是使用示例数据的SQL Fiddle示例。