Skip to content
Advertisement

How to calculate running sum for each group in MySQL

Straightforward summation I can do with sum() function. But I’ve a different situation here. I’ve a table Student with only 2 fields. For instance just assume that there is only 1 student in the entire class:

CREATE TABLE student
    (`dateOfExam` date, score int)
;
    
INSERT INTO student
    (`dateOfExam`, `score`)
VALUES
    ('2020-05-28',5),
    ('2020-05-29',5),
    ('2020-05-30',10),
    ('2020-06-03',10),
    ('2020-06-05',5),
    ('2020-07-21',20),
    ('2020-07-22',10),
    ('2020-07-28',10)
;

And I have his scores for the days when exams were taken with one more column in the runtime which is the month in which exam was held:

The query is (took help from stackoverflow yesterday):

select date_format(dateOfExam, '%Y-%m') ExamMonth
     , dateOfExam
     , score 
  from student;

Result:

+-----------+------------+-------+
| ExamMonth | dateOfExam | score |
+-----------+------------+-------+
| 2020-05   | 2020-05-28 |     5 |
| 2020-05   | 2020-05-29 |     5 |
| 2020-05   | 2020-05-30 |    10 |
| 2020-06   | 2020-06-03 |    10 |
| 2020-06   | 2020-06-05 |     5 |
| 2020-07   | 2020-07-21 |    20 |
| 2020-07   | 2020-07-22 |    10 |
| 2020-07   | 2020-07-28 |    10 |
+-----------+------------+-------+

My requirement is I want to reward this student every month. I’ll keep on adding his score for each date for each individual month and give him Reward1 when accumulated score sum reaches 10 and Reward2 when accumulated score sum reaches 20. So the final table should like this:

+---------------+---------------+-------+---------------+---------------+
| ExamMonth     |  dateOfExam   | Score |    Reward1    |   Reward2     |
+---------------+---------------+-------+---------------+---------------+
|    2020-05    |  2020-05-28   |   5   |               |               |
|               |  2020-05-29   |   5   |       Y       |               |
|               |  2020-05-30   |   10  |               |       Y       |
|---------------|---------------|-------|---------------|---------------|
|    2020-06    |  2020-06-03   |   10  |       Y       |               |
|               |  2020-06-05   |   5   |               |               |
|---------------|---------------|-------|---------------|---------------|
|    2020-7     |  2020-07-21   |   20  |       Y       |       Y       |
|               |  2020-07-22   |   10  |               |               |
|               |  2020-07-28   |   10  |               |               |
+---------------+---------------+-------+---------------+---------------+

Reward fields can be boolean and empty reward rows can be set to N or False or whatever seems logical. This was not helpful: Calculate running sum

Please help me achieve this objective. Suggest some approach.

Here is a fiddle.

Advertisement

Answer

First calculate the running sum of the scores for each month in a CTE.
Then apply your conditions:

with cte as (
  select date_format(dateOfExam, '%Y-%m') ExamMonth,
         dateOfExam, score, 
         sum(score) over (partition by date_format(dateOfExam, '%Y-%m') order by dateOfExam) total
  from student
)
select ExamMonth, dateOfExam, score, 
       case when sum(total >= 10) over (partition by ExamMonth order by dateOfExam) = 1 then 'Y' end Reward1,
       case when sum(total >= 20) over (partition by ExamMonth order by dateOfExam) = 1 then 'Y' end Reward2
from cte

See the demo.
Results:

> ExamMonth | dateOfExam | score | Reward1 | Reward2
> :-------- | :--------- | ----: | :------ | :------
> 2020-05   | 2020-05-28 |     5 | null    | null   
> 2020-05   | 2020-05-29 |     5 | Y       | null   
> 2020-05   | 2020-05-30 |    10 | null    | Y      
> 2020-06   | 2020-06-03 |    10 | Y       | null   
> 2020-06   | 2020-06-05 |     5 | null    | null   
> 2020-07   | 2020-07-21 |    20 | Y       | Y      
> 2020-07   | 2020-07-22 |    10 | null    | null   
> 2020-07   | 2020-07-28 |    10 | null    | null 
User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement