如何计算 MySQL 中每个组的 运行 总和
How to calculate running sum for each group in MySQL
我可以使用 sum()
函数进行直接求和。但我这里有不同的情况。我有一个只有 2 个字段的 table Student。例如假设整个 class:
只有 1 个学生
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)
;
我有他的 分数 参加考试的日子,在运行时间中多了一列,即举行考试的月份:
查询是(昨天从 Whosebug 获得帮助):
select date_format(dateOfExam, '%Y-%m') ExamMonth
, dateOfExam
, score
from student;
结果:
+-----------+------------+-------+
| 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 |
+-----------+------------+-------+
我的要求是每个月都要奖励这个学生。我会继续为每个月的每个日期添加他的分数,当累计分数达到 10 时给他 Reward1,当累计分数达到 Reward2总和达到 20。所以最后的 table 应该是这样的:
+---------------+---------------+-------+---------------+---------------+
| 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 | | |
+---------------+---------------+-------+---------------+---------------+
奖励字段可以是布尔值,空奖励行可以设置为 N 或 False 或任何看起来符合逻辑的值。
这没有帮助:
Calculate running sum
请帮我实现这个 objective。建议一些方法。
这里是fiddle.
以下代码片段按 ExamMonth 上的基本查询分组,然后在决定 Reward1 和 Reward2 的值时使用一个案例。此查询仅供参考。请重写为最适合你的。
select DERIVED2.ExamMonth, CASE WHEN DERIVED2.Cumul_Score >= 10 THEN 'Y'
ELSE ''
END AS Rewards1,
CASE WHEN DERIVED2.Cumul_Score >= 20 THEN 'Y'
ELSE ''
END AS Rewards2
FROM
(
select DERIVED1.ExamMonth, SUM(DERIVED1.score) as Cumul_Score
FROM
(
select date_format(dateOfExam, '%Y-%m') ExamMonth,
dateOfExam, score
from student
order by dateOfExam
) DERIVED1
GROUP BY ExamMonth
) DERIVED2
首先计算 CTE 中每个月的 运行 分数总和。
然后应用您的条件:
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
参见demo。
结果:
> 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
我可以使用 sum()
函数进行直接求和。但我这里有不同的情况。我有一个只有 2 个字段的 table Student。例如假设整个 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)
;
我有他的 分数 参加考试的日子,在运行时间中多了一列,即举行考试的月份:
查询是(昨天从 Whosebug 获得帮助):
select date_format(dateOfExam, '%Y-%m') ExamMonth
, dateOfExam
, score
from student;
结果:
+-----------+------------+-------+
| 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 |
+-----------+------------+-------+
我的要求是每个月都要奖励这个学生。我会继续为每个月的每个日期添加他的分数,当累计分数达到 10 时给他 Reward1,当累计分数达到 Reward2总和达到 20。所以最后的 table 应该是这样的:
+---------------+---------------+-------+---------------+---------------+
| 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 | | |
+---------------+---------------+-------+---------------+---------------+
奖励字段可以是布尔值,空奖励行可以设置为 N 或 False 或任何看起来符合逻辑的值。 这没有帮助: Calculate running sum
请帮我实现这个 objective。建议一些方法。
这里是fiddle.
以下代码片段按 ExamMonth 上的基本查询分组,然后在决定 Reward1 和 Reward2 的值时使用一个案例。此查询仅供参考。请重写为最适合你的。
select DERIVED2.ExamMonth, CASE WHEN DERIVED2.Cumul_Score >= 10 THEN 'Y'
ELSE ''
END AS Rewards1,
CASE WHEN DERIVED2.Cumul_Score >= 20 THEN 'Y'
ELSE ''
END AS Rewards2
FROM
(
select DERIVED1.ExamMonth, SUM(DERIVED1.score) as Cumul_Score
FROM
(
select date_format(dateOfExam, '%Y-%m') ExamMonth,
dateOfExam, score
from student
order by dateOfExam
) DERIVED1
GROUP BY ExamMonth
) DERIVED2
首先计算 CTE 中每个月的 运行 分数总和。
然后应用您的条件:
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
参见demo。
结果:
> 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