每个月中每个唯一ID的累计总和

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每个月中每个唯一ID的累计总和相关的知识,希望对你有一定的参考价值。

我试图计算所有客户的累积利润,我从here找到了一个非常好的参考。但是,我的表由超过1个客户组成,应该有自己的累计利润。下面是我已经拥有的“客户”表。

| Year | Month | id  | profit | cumulative |
| 2017 |   1   | 123 |  1000  |            |
| 2017 |   2   | 123 |  -200  |            |
| 2017 |   3   | 123 |  500   |            |
| 2017 |   1   | 456 |  500   |            |
| 2017 |   2   | 456 |  100   |            |
| 2017 |   3   | 456 |  200   |            |

如果我使用这样的SQL代码:

SET @csum := 0;
UPDATE client
SET cumulative = (@csum := @csum + profit);

我得到的结果是这样的:

| Year | Month | id  | profit | cumulative |
| 2017 |   1   | 123 |  1000  |    1000    |
| 2017 |   2   | 123 |  -200  |    800     |
| 2017 |   3   | 123 |  500   |    1300    |
| 2017 |   1   | 456 |  500   |    1800    |
| 2017 |   2   | 456 |  100   |    1900    |
| 2017 |   3   | 456 |  200   |    2100    |

我期望得到的是这样的:

| Year | Month | id  | profit | cumulative |
| 2017 |   1   | 123 |  1000  |    1000    |
| 2017 |   2   | 123 |  -200  |    800     |
| 2017 |   3   | 123 |  500   |    1300    |
| 2017 |   1   | 456 |  500   |    500     |
| 2017 |   2   | 456 |  100   |    600     |
| 2017 |   3   | 456 |  200   |    800     |

我也试图按年,月和ID对它进行分组,但它不起作用。基本上,我想要每个月的每个独特客户的累计金额。你知道如何解决这个问题吗?提前致谢。

答案

局部变量仅在查询中与ORDER BY一起正常工作。

SET @csum := 0, @id:=NULL;
UPDATE client
   SET cumulative = (@csum := if(id=@id,@csum,0) + profit), id=(@id:=id)
ORDER BY id, year, month;

关于sqlfiddle.com的例子

或者更短:... SET cumulative = (@csum := if(id=@id, @csum, 0*(@id:=id) ) + profit)。此comare存储ID与当前ID,如果ID相同则返回存储的SUM,如果ID不同则返回0(并存储新ID)。

另一答案

我会避免局部变量,因为结果有时可能与预期不同,并且DBMS可以更好地优化基于集合的方法。使用子查询或自联接:

SELECT c1.*,
       (SELECT SUM(c2.profit)
        FROM client c2
        WHERE (c2.year < c1.year or 
              (c2.year = c1.year and c2.month <= c1.month)) and 
              c2.id = c1.id
       ) AS cumulative_sum
FROM TABLE client c1

因此在update它可以这样

UPDATE client
JOIN
(
   SELECT c1.id, c1.year, c1.month,
       (SELECT SUM(c2.profit)
        FROM client c2
        WHERE (c2.year < c1.year or 
              (c2.year = c1.year and c2.month <= c1.month)) and 
              c2.id = c1.id
       ) AS cumulative_sum
   FROM client c1
) t ON client.id = t.id and
     client.year = t.year and
     client.month = t.month
SET cumulative = t.cumulative_sum

sqlfiddle demo(感谢@JohnWoo的数据)

另一答案

您可以使用变量执行此操作,但您需要非常小心。使用变量时,您希望所有操作都在一个语句中 - 因为mysql不保证语句的评估顺序:

SET @csum := 0;
SET @id := -1;

UPDATE client c
    SET cumulative = (CASE WHEN @id = id
                           THEN @csum := @csum + profit
                           WHEN @id := id
                           THEN @csum := profit
                           ELSE @csum := profit
                      END)
    ORDER BY id, year, month;

以上是关于每个月中每个唯一ID的累计总和的主要内容,如果未能解决你的问题,请参考以下文章

SQL累计总和每天刷新每个用户的新余额

XSLT 2.0 如何对每个唯一项目 id 的计数求和

如何在 MySQL 中发现一个月中每一天的总和?

如何在employee_id上 进行内部联接时获取每个唯一员工的销售总额

java,计算一个月中每一天商品的数量

创建 2、3 或 4 列的每个唯一组合的总和