不能累计求和`COUNT(*)`

时间:2014-07-31 15:22:58

标签: mysql sql group-by aggregate-functions cumulative-sum

this answer的第二部分使用变量来创建另一列的累积和。我做同样的事情,除了我使用GROUP BY语句,并且总结COUNT(*)而不是列。这是我创建最小表和插入值的代码:

CREATE TABLE `test_group_cumulative` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    `group_id` int(11) unsigned NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `test_group_cumulative` (`id`, `group_id`)
VALUES
    (1, 1),
    (2, 2),
    (3, 3);

这是失败的代码:

SELECT
    `group_id`,
    COUNT(*) AS `count`,
    @count_cumulative := @count_cumulative + COUNT(*) AS `count_cumulative`
FROM `test_group_cumulative` AS `tgc`
JOIN (SELECT @count_cumulative := 0) AS `_count_cumulative`
GROUP BY `group_id`
ORDER BY `id`;

结果如下:

group_id    count   count_cumulative
1   1   1
2   1   1
3   1   1

如您所见,count_cumulative未正确汇总。但是,这是一个奇怪的部分。如果我将COUNT(*)中的count_cumulative替换为1的{​​{1}},则查询可以正常运行。

    @count_cumulative := @count_cumulative + 1 AS `count_cumulative`

这是正确的结果:

group_id    count   count_cumulative
1   1   1
2   1   2
3   1   3

显然,在我的应用中,每个组中都会有多个项目,因此COUNT(*)不会永远是1。我知道有很多方法可以使用连接或子查询来完成此操作,如果必须的话,我会这样做,但在我看来,这应该是可行的。那么为什么没有COUNT(*)在累积金额内工作呢?

2 个答案:

答案 0 :(得分:2)

我同意@Ashalynd,count(*)的值尚未评估。这是我做的一个小实验:

1.
    SELECT
        GROUP_ID,    
        @COUNTER := @COUNTER + COUNT(*)  GROUPCOUNT,
        @COUNTER COUNTER
     FROM
        TEST_GROUP_CUMULATIVE, 
        (SELECT @COUNTER := 0) R
    GROUP BY
        GROUP_ID;

-- RESULT
============

   GROUP_ID    GROUPCOUNT    COUNTER
  ------------------------------------     
   1           1             0
   2           1             0
   3           1             0

2.
    SELECT @COUNTER;

    -- RESULT
    =============

    @COUNTER
    --------
    1

对于每个组,变量初始化为0.这意味着COUNT(*)尚未被评估。

此外,当你这样做时:

 1.
    SELECT
        GROUP_ID,    
        @COUNTER := @COUNTER + 1  GROUPCOUNT,
        @COUNTER COUNTER
     FROM
        TEST_GROUP_CUMULATIVE, 
        (SELECT @COUNTER := 0) R
    GROUP BY
        GROUP_ID;

-- RESULT
============
   GROUP_ID    GROUPCOUNT    COUNTER
  ------------------------------------     
   1           1             1
   2           1             2
   3           1             3

2.    
SELECT @COUNTER;

    -- RESULT
    =============

    @COUNTER
    --------
    3

它不需要评估1.它直接总结它,它给你累积的总和。

答案 1 :(得分:1)

这是我在进行时间序列分析时经常遇到的问题。解决这个问题的首选方法是将其包装到第二个选择中,并在最后一层引入计数器。如果需要,您可以使用临时表将此技术调整为更复杂的数据流。

我使用您提供的架构完成了这个小型的sqlfiddle:http://sqlfiddle.com/#!2/cc97e/21

以下是获取累积计数的查询:

SELECT
tgc.group_id, @count_cumulative := @count_cumulative + cnt as cum_cnt
FROM (
  SELECT
    group_id, COUNT(*) AS cnt
  FROM `test_group_cumulative` 
  group by group_id
  order by id) AS `tgc`, 
(SELECT @count_cumulative := 0) AS `temp_var`; 

这是我得到的结果:

GROUP_ID    CUM_CNT
1           1
2           2
3           3

您的尝试不起作用的原因:

当你使用临时变量执行分组时,mysql独立地执行各个组,并且在每个组分配临时变量当前值时,在这种情况下为0。

如果,您运行了此查询:

SELECT @count_cumulative;

后立即

SELECT
    `group_id`,
    COUNT(*) AS `count`,
    @count_cumulative := @count_cumulative + COUNT(*) AS `count_cumulative`
FROM `test_group_cumulative` AS `tgc`
JOIN (SELECT @count_cumulative := 0) AS `_count_cumulative`
GROUP BY `group_id`
ORDER BY `id`;

您将获得值1.对于每个组,@ count_cumulative将重置为0.

因此,在我提出的解决方案中,我首先通过生成'group-counts'然后进行累积来规避这个问题。