2014-03-05 120 views
1

我有一個查詢,顯示通過我的系統去年發送了多少個消息,按月分組。完美的作品!按2列分組

結果看起來像這樣:

+------+-------+--------+--------+--------+ 
| Year | Month | Type 1 | Type 2 | Type 3 | 
+------+-------+--------+--------+--------+ 
| 2013 | 10 |  0 |  2 |  3 | 
| 2013 | 11 |  4 |  21 |  56 | 
| 2013 | 12 |  1 |  10 |  16 | 
| 2014 |  1 |  2 |  10 |  52 | 
| 2014 |  2 |  1 |  62 | 118 | 
+------+-------+--------+--------+--------+ 

(類型1,2和3是簡單地不同類型的用戶-ignore此)

然而,我想避免所述相同的接收器(msg_receiver)可以在結果集中顯示兩次,每個月。

因此,如果用戶44和39在12月向用戶70發送消息,則user_id 70將僅在12月被計數一次。目前,他將出現兩次。

下面是我的查詢:

SELECT 
    Year(m.msg_date) as year, 
    Month(m.msg_date) as month, 
    sum(u.type = '1') as type_1, 
    Sum(u.type = '2') as type_2, 
    sum(u.type = '7') as type_3 
FROM 
    messages m 
INNER JOIN 
    users u ON u.user_id = m.msg_sender 
WHERE 
    m.msg_date >= CURDATE() - INTERVAL 1 YEAR 
    AND month(msg_date) != month(curdate()) 
GROUP BY 
    Month(m.msg_date) -- , m.msg_receiver (this does not work, it will no longer group by each month/year). 
ORDER BY 
    msg_date 

邏輯答案,就在我的選擇是,以第一組由一個月,然後USER_ID(或副通過)。但如果我這樣做,結果看起來很奇怪。請參閱:

使用GROUP BY Month(m.msg_date), u.user_id

+------+-------+--------+--------+--------+ 
| Year | Month | Type 1 | Type 2 | Type 3 | 
+------+-------+--------+--------+--------+ 
| 2013 | 10 |  0 |  1 |  0 | 
| 2013 | 10 |  0 |  0 |  1 | 
| 2013 | 10 |  0 |  0 |  1 | 
| 2013 | 10 |  0 |  1 |  0 | 
| 2013 | 10 |  0 |  0 |  1 | 
| 2013 | 11 |  0 |  0 |  19 | 
| 2013 | 11 |  0 |  1 |  0 | 
| 2013 | 11 |  0 |  1 |  0 | 
| 2013 | 11 |  0 |  1 |  0 | 
| 2013 | 11 |  0 |  1 |  0 | 
| 2013 | 11 |  2 |  0 |  0 | 
| 2013 | 11 |  0 |  0 |  11 | 
+------+-------+--------+--------+--------+ 

它沒有GROUP BY個月了,因爲它應該。

任何想法?

編輯

只是爲了澄清我想要什麼來實現的,因爲人們已經有點糊塗了。想象一下這種情況:

It is December 2013. 

USER 1 has written 5 messages to USER 2 (this should count as 1 in december) 
USER 4 has written 1 message to USER 4 (this should count as 1 in december) 
USER 3 has written 2 messages to USER 4 and 2 (this should count as 2 in december). 

The totals of the month would then be 4. Because there has been 4 conversations.  

它有道理嗎?我發現我的自我經常在如何正確表達我的自我和理解方面掙扎。

+0

考慮提供適當的DDL(和/或sqlfiddle)連同所需的結果集 – Strawberry

+1

爲了回答這個問題 - 一個問題 - 如果接收方發送多條消息,並且每條消息都是不同的類型,那麼您要計算接收方的類型? – user158017

+0

我明白了,對於混亂感到抱歉。我編輯了我的答案來解釋 – FooBar

回答

3

您可以使用COUNT(DISTINCT只計算每個msg_receiver每個類型一次:

SELECT 
    Year(m.msg_date) as year, 
    Month(m.msg_date) as month, 
    COUNT(DISTINCT CASE WHEN u.type = '1' THEN m.msg_receiver END) as type_1, 
    COUNT(DISTINCT CASE WHEN u.type = '2' THEN m.msg_receiver END) as type_2, 
    COUNT(DISTINCT CASE WHEN u.type = '3' THEN m.msg_receiver END) as type_3 
FROM 
    messages m 
INNER JOIN 
    users u ON u.user_id = m.msg_sender 
WHERE 
    m.msg_date >= CURDATE() - INTERVAL 1 YEAR 
    AND month(msg_date) != month(curdate()) 
GROUP BY 
    Year(m.msg_date), Month(m.msg_date) 
ORDER BY 
    msg_date 

注:我已經添加Year(m.msg_date)到你的小組,確保到的結果是確定的

如果同一用戶接收來自兩個不同用戶的消息有兩種不同的類型,但它們將被計入兩種類型。如果這不是預期的結果,您需要拿出一些邏輯來確定它們應該計入哪種類型(最小,最大,模式,中位數等)

例如,如果您想要最小用戶類型,你可以使用:

SELECT 
    m.year, 
    m.month, 
    sum(m.type = '1') as type_1, 
    Sum(m.type = '2') as type_2, 
    sum(m.type = '7') as type_3 
FROM ( 
     SELECT 
      Year(m.msg_date) as year, 
      Month(m.msg_date) as month, 
      m.msg_receiver, 
      MIN(u.type) AS type 
     FROM 
      messages m 
     INNER JOIN 
      users u ON u.user_id = m.msg_sender 
     WHERE 
      m.msg_date >= CURDATE() - INTERVAL 1 YEAR 
      AND month(msg_date) != month(curdate()) 
     GROUP BY 
      Year(m.msg_date), Month(m.msg_date), m.msg_receiver 
    ) m 
GROUP BY 
    m.Year, m.Month 
ORDER BY 
    m.year, m.month; 

編輯

針對更新的問題,以目前的形式我的第一個答案會算你的例子,因爲只有3談話不是4,因爲當時只有3獨一無二收件人。你真正需要的是能夠對發送者和接收者進行統計,即count(distinct m.msg_sender, m.msg_sender)。不幸的是,這是非法的語法,但是,你基本上可以通過連接兩個字段(只要它們是由不能出現在任何一個字符/字符分隔達到同樣的事情。例如

SELECT 
    Year(m.msg_date) as year, 
    Month(m.msg_date) as month, 
    COUNT(DISTINCT CASE WHEN u.type = '1' THEN CONCAT(m.msg_sender, '|', m.msg_receiver) END) as type_1, 
    COUNT(DISTINCT CASE WHEN u.type = '2' THEN CONCAT(m.msg_sender, '|', m.msg_receiver) END) as type_2, 
    COUNT(DISTINCT CASE WHEN u.type = '3' THEN CONCAT(m.msg_sender, '|', m.msg_receiver) END) as type_3 
FROM 
    messages m 
INNER JOIN 
    users u ON u.user_id = m.msg_sender 
WHERE 
    m.msg_date >= CURDATE() - INTERVAL 1 YEAR 
    AND month(msg_date) != month(curdate()) 
GROUP BY 
    Year(m.msg_date), Month(m.msg_date) 
ORDER BY 
    msg_date 
+0

看起來這正是我想要實現的。我會玩一會兒,看看它是否有效。很好的答案。另外,我已經更新了我的答案,以解釋我確切要計算的內容。 – FooBar

+0

你是我的英雄,謝謝你。 – FooBar

0

你的天堂」牛逼發佈的數據結構,但現在看來,要改變INNER JOIN到

INNER JOIN 
    users u ON u.user_id = m.msg_receiver