mysql查询中的组计数的累积和

时间:2014-09-12 11:25:01

标签: mysql sql count sum

我的桌子看起来如下......

ID HID  Date          UID
 1  1   2012-01-01    1002
 2  1   2012-01-24    2005
 3  1   2012-02-15    5152
 4  2   2012-01-01    6252
 5  2   2012-01-19    10356
 6  3   2013-01-06    10989
 7  3   2013-03-25    25001
 8  3   2014-01-14    35798 

如何按HID,年,月和计数(UID)分组并添加cumulative_sum(这是UID的计数)。所以最终的结果看起来像这样......

HID  Year   Month   Count  cumulative_sum
1   2012   01      2      2
1   2012   02      1      3
2   2012   01      2      2
3   2013   01      1      1
3   2013   03      1      2
3   2014   01      1      3   

使用查询完成此操作的最佳方法是什么?

2 个答案:

答案 0 :(得分:5)

我对原始数据集做了假设。您应该能够将其调整为修订后的数据集 - 尽管请注意使用变量(而不是我的自联接)的解决方案更快...

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(ID INT NOT NULL  
,Date DATE NOT NULL          
,UID INT NOT NULL PRIMARY KEY
);

INSERT INTO my_table VALUES
(1   ,'2012-01-01',    1002),
(1   ,'2012-01-24',    2005),
(1   ,'2012-02-15',    5152),
(2   ,'2012-01-01',    6252),
(2   ,'2012-01-19',    10356),
(3   ,'2013-01-06',    10989),
(3   ,'2013-03-25',    25001),
(3   ,'2014-01-14',    35798);


SELECT a.*
     , SUM(b.count) cumulative 
  FROM
     (
       SELECT x.id,YEAR(date) year,MONTH(date) month, COUNT(0) count FROM my_table x GROUP BY  id,year,month
     ) a
  JOIN
     (
       SELECT x.id,YEAR(date) year,MONTH(date) month, COUNT(0) count FROM my_table x GROUP BY  id,year,month
     ) b
    ON b.id = a.id AND (b.year < a.year OR (b.year = a.year AND b.month <= a.month)
     )
 GROUP 
    BY a.id, a.year,a.month;
+----+------+-------+-------+------------+
| id | year | month | count | cumulative |
+----+------+-------+-------+------------+
|  1 | 2012 |     1 |     2 |          2 |
|  1 | 2012 |     2 |     1 |          3 |
|  2 | 2012 |     1 |     2 |          2 |
|  3 | 2013 |     1 |     1 |          1 |
|  3 | 2013 |     3 |     1 |          2 |
|  3 | 2014 |     1 |     1 |          3 |
+----+------+-------+-------+------------+

如果您不介意结果中的额外列,您可以简化(并加速)上述内容,如下所示:

SELECT x.*
     , @running:= IF(@previous=x.id,@running,0)+x.count cumulative
     , @previous:=x.id
  FROM 
     ( SELECT x.id,YEAR(date) year,MONTH(date) month, COUNT(0) count FROM my_table x GROUP BY  id,year,month ) x
    ,( SELECT @cumulative := 0,@running:=0) vals;

答案 1 :(得分:1)

代码变得混乱,如下所示:

SELECT
    HID,
    strftime('%Y', `Date`) AS Year,
    strftime('%m', `Date`) AS Month,
    COUNT(UID) AS Count,
    (SELECT
        COUNT(UID)
    FROM your_db A
    WHERE
            A.HID=B.HID
        AND
                (strftime('%Y', A.`Date`) < strftime('%Y', B.`Date`)
            OR
                    (strftime('%Y', A.`Date`) = strftime('%Y', B.`Date`)
                AND
                    strftime('%m', A.`Date`) <= strftime('%m', B.`Date`)))) AS cumulative_count
FROM your_db B
GROUP BY HID, YEAR, MONTH

虽然通过使用视图,它应该变得更加清晰:

CREATE VIEW temp_data AS SELECT
    HID,
    strftime('%Y', `Date`) as Year,
    strftime('%m', `Date`) as Month,
    COUNT(UID) as Count
FROM your_db GROUP BY HID, YEAR, MONTH;

然后你的陈述如下:

SELECT
    HID,
    Year,
    Month,
    `Count`,
    (SELECT SUM(`Count`)
FROM temp_data A
WHERE
        A.HID = B.HID
    AND
            (A.Year < B.Year
        OR
                (A.Year = B.Year
            AND
                A.Month <= B.Month))) AS cumulative_sum
FROM temp_data B;