按2列分组

时间:2014-03-05 15:48:50

标签: mysql sql

我有一个查询,显示去年通过我的系统发送了多少条消息,按月分组。效果很好!

结果如下:

+------+-------+--------+--------+--------+
| 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只是不同类型的USERS - 以此为准)

但是,我想避免每个月在结果集中显示两次相同的接收器(msg_receiver)。

因此,如果用户44和39在12月向用户70发送消息,则user_id 70将仅计算在12月的ONCE。目前,他将出现两次。

以下是我的询问:

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 |
+------+-------+--------+--------+--------+

它不再按月分组,因为它应该。

有什么想法吗?

修改

只是为了澄清我想要实现的目标,因为人们有点困惑。想象一下这种情况:

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.    

有意义吗?我发现自己经常在如何正确地表达自我和理解中苦苦挣扎。

2 个答案:

答案 0 :(得分: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

N.B我已将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

答案 1 :(得分:0)

您尚未发布数据结构,但似乎您想要将INNER JOIN更改为

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