簡體   English   中英

MySQL Join三個表返回多個結果

[英]MySQL Join three tables return multiple results

我有三個表:我們稱其為CUSTOMER,LOG和REVIEW

客戶表為:

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

您的查詢正在做的是加入評論並登錄客戶,而兩者之間沒有加入條件。 這意味着您將使用給定客戶的每個評論來創建每個日志的笛卡爾乘積(例如,您希望John獲得的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

如果您在沒有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只算一次!

這應該給您您需要的:

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

每當您遇到這樣的復雜查詢時,我總是建議您先將其分解成幾部分,然后再放回去。

例如,要獲取單個表的每個客戶的計數,可以使用以下聚合:

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

您可以進行同樣的操作以進行審查,最后,將這些結果外聯到customer表以獲取其名稱。 您應該使用外部聯接的原因是因為用戶可能在其他表中沒有任何條目。 因此,您應該使用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示例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM