MySQL聚合函数针对不同的组,应该从最外面的GROUP BY计算?

时间:2015-12-02 10:36:43

标签: mysql sql group-by

我有下表table

| id   | id_a | id_b  | date       | day_part | 
===============================================
 32043 |    0 |     0 | 2015-12-03 |    A     |
 31933 |    0 | 31933 | 2015-12-03 |    A     |
 31908 |    0 |     0 | 2015-12-03 |    A     | 
 31384 |    0 | 31384 | 2015-11-30 |    M     |
 31335 |    0 |     0 | 2015-11-30 |    M     |
 31303 |    0 | 31303 | 2015-11-30 |    M     |
 31302 |    0 |     0 | 2015-11-30 |    M     |  
 31300 |    0 |     0 | 2015-11-30 |    M     |
 31223 |    0 |     0 | 2015-12-03 |    A     |
 31221 |    0 | 31221 | 2015-11-30 |    M     |
 32037 |    0 | 32037 | 2015-12-03 |    A     |
 31301 | 31301|     0 | 2015-11-30 |    M     |
 31901 | 31301|     0 | 2015-11-30 |    M     |

id是唯一ID,day_part是指当天的部分('A'表示'下午','M'表示'早上')。

假设我的日期范围介于2015-11-302015-12-06之间。

对于每一天,我需要找到每个COUNT的{​​{1}}字段的id

day_part

我可以轻松地做到:

|  date     | M_ids_count | A_ids_count |
=========================================
 2015-11-30 | 8           | 0
 2015-12-03 | 0           | 5

现在棘手的部分是:

我需要返回以下结果:

SELECT 
    date,
    SUM(CASE WHEN day_part = 'M' THEN 1 ELSE 0 END) AS M_ids_count,
    SUM(CASE WHEN day_part = 'A' THEN 1 ELSE 0 END) AS A_ids_count
FROM table
WHERE date BETWEEN '2015-11-30' AND '2015-12-06'
AND day_part IN ("M", "A")
GROUP BY date;

我们现在已经开始计算| date | M_ids_count | A_ids_count | M_trips_count | A_trips_count | ========================================================================= 2015-11-30 | 8 | 0 | 7 | 0 2015-12-03 | 0 | 5 | 0 | 5 M_ids_count

A_ids_count与第n M_trips_count和第n date相关,并按以下方式计算:

  • 条件1:如果我对同一day_partid_a有相同的date,我需要求和day_part(即,我在这里);

  • 条件2:如果我1id_a并且我有相同的0,我需要总结id_b(当然,例如,如果我有1 = 0和三个不同的id_a,我需要总结id_b);

  • 条件3:否则,如果3id_aid_b,我需要对记录的0求和;

COUNTA_trips_count也是如此,但它与下午A_trips_count的{​​{1}}有关。

因此,在我们的情况下,如果您查看date,您会看到两个字段day_parttable 31301 31901 < / strong>)具有相同的id_a = 31301id。这将计算date,因为它符合day_part的要求。

然后,应将此1添加到符合Condition 1的同一1COUNT Condition 2的记录date中:day_part3 s 31384,31303,31221)。这里我们总共有id

然后,应将此4添加到符合4的同一COUNTCondition 3 date的记录day_part中:3id s - &gt; 31335,31302和31300)。

因此,我们得到7 M_trips_count的值2015-11-30M day_part(即早晨)。同一A_trips_count的{​​{1}}计算应相同,但与下午相关。

然后,datedates之间的另一个2015-11-30也是如此(在我们的例子中仅针对2015-12-06 date不是其他日期)。与2015-12-03相同的M_trips_countA_trips_count计算。

现在,我可以/如何只使用一个SQL查询来完成它?

我需要的结果是(与上面相同):

2015-11-30

感谢您的关注!

1 个答案:

答案 0 :(得分:1)

尝试以下代码大部分都可以使用。

SELECT t.dp AS date_part,
    SUM(t.M_ids_count) AS M_ids_count, 
    SUM(t.A_ids_count) AS A_ids_count,
    SUM(IF(t.M_trip_count = 'M_NULL', 0, (IF(t.M_trip_count = 'M_SAME', t.M_ids_count, 1)))) AS M_trip_count,
    SUM(IF(t.A_trip_count = 'A_NULL', 0, (IF (t.A_trip_count = 'A_SAME', t.A_ids_count, 1)))) AS A_trip_count
FROM (
    SELECT 
        date_part AS dp,
        SUM(CASE WHEN day_part = 'M' THEN 1 ELSE 0 END) AS M_ids_count,
        SUM(CASE WHEN day_part = 'A' THEN 1 ELSE 0 END) AS A_ids_count,
        (CASE WHEN (day_part = 'M') THEN (IF(((id_a = 0 AND id_b = 0) OR (id_a = id_b)), 'M_SAME', 'M_DIFF')) ELSE 'M_NULL' END) AS M_trip_count,
        (CASE WHEN (day_part = 'A') THEN (IF(((id_a = 0 AND id_b = 0) OR (id_a = id_b)), 'A_SAME', 'A_DIFF')) ELSE 'A_NULL' END) AS A_trip_count
    FROM timer
    WHERE date_part BETWEEN '2015-11-30' AND '2015-12-06' AND day_part IN ("M", "A")
    GROUP BY id_a,id_b,M_trip_count,A_trip_count
) AS t 
GROUP BY t.dp

这将按照您在上表中指定的表结构工作。

CREATE TABLE IF NOT EXISTS `timer` (
  `id` int(11) NOT NULL,
  `id_a` int(11) NOT NULL,
  `id_b` int(11) NOT NULL,
  `date_part` date NOT NULL,
  `day_part` varchar(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `timer` (`id`, `id_a`, `id_b`, `date_part`, `day_part`) VALUES
(32043, 0, 0, '2015-12-03', 'A'),
(31933, 0, 31933, '2015-12-03', 'A'),
(31908, 0, 0, '2015-12-03', 'A'),
(31384, 0, 31384, '2015-11-30', 'M'),
(31335, 0, 0, '2015-11-30', 'M'),
(31303, 0, 31303, '2015-11-30', 'M'),
(31302, 0, 0, '2015-11-30', 'M'),
(31300, 0, 0, '2015-11-30', 'M'),
(31223, 0, 0, '2015-12-03', 'A'),
(31221, 0, 31221, '2015-11-30', 'M'),
(32037, 0, 32037, '2015-12-03', 'A'),
(31301, 31301, 0, '2015-11-30', 'M'),
(31901, 31301, 0, '2015-11-30', 'M');