Search code examples
mysqlsqlgroup-byinner-joincumulative-sum

Custom cumulative sum in php


I have had success with cumulative sum in php mysql.

+---+---------+
| id| SomeNumt|
+---+---------+
|  1|       10|
|  2|       12|
|  3|        3|
|  4|       15|
|  5|       23|
+---+---------+

SELECT t1.id,
       t1.SomeNumt,
       SUM(t2.SomeNumt) AS SUM
FROM t t1
INNER JOIN t t2 ON t1.id >= t2.id
GROUP BY t1.id,
         t1.SomeNumt
ORDER BY t1.id

Output:

+---+---------+--------+
| id| SomeNumt|     SUM|
+---+---------+--------+
|  1|       10|      10|
|  2|       12|      22|
|  3|        3|      25|
|  4|       15|      40|
|  5|       23|      63|
+---+---------+--------+

Now I have a little problem, when I custom query (WHERE t1.SomeNumt>3)

...
INNER JOIN t t2 ON t1.id >= t2.id
WHERE t1.SomeNumt>3
...

Out put is wrong

+---+---------+--------+
| id| SomeNumt|     SUM|
+---+---------+--------+
|  1|       10|      10|
|  2|       12|      22|
|  4|       15|      40|
|  5|       23|      63|
+---+---------+--------+

But I was expecting:

+---+---------+--------+
| id| SomeNumt|     SUM|
+---+---------+--------+
|  1|       10|      10|
|  2|       12|      22|
|  4|       15|      37|   -- 10+22+15
|  5|       23|      60|   -- 10+22+15+23
+---+---------+--------+

How to fix?


Solution

  • You need to apply the same condition to t2:

    SELECT t1.id,
           t1.SomeNumt,
           SUM(t2.SomeNumt) AS SUM
    FROM t t1
    INNER JOIN t t2 ON t1.id >= t2.id
    WHERE t1.SomeNumt > 3 AND t2.SomeNumt > 3
    GROUP BY t1.id,
             t1.SomeNumt
    ORDER BY t1.id
    

    Alternatively you can apply the condition in a subquery:

    SELECT t1.id,
           t1.SomeNumt,
           SUM(t2.SomeNumt) AS SUM
    FROM (SELECT * FROM t WHERE SomeNumt > 3) t1
    INNER JOIN (SELECT * FROM t WHERE SomeNumt > 3) t2 ON t1.id >= t2.id
    GROUP BY t1.id,
             t1.SomeNumt
    ORDER BY t1.id
    

    Output (for both queries):

    id  SomeNumt    SUM
    1   10          10
    2   12          22
    4   15          37
    5   23          60
    

    Demo on dbfiddle

    If you're using MySQL 8+, you should use window functions as described in @GordonLinoff's answer.