sql 纵向求和_SQL 累计求和

今天看到有群友在群里了这个问题,问题描述见下图。这种需求在做报表统计时经常会遇到,会的人觉得不难,没有接触过可能会被困住,所以我把它拿出来和大家分享。

图中已把问题描述清楚,再结合数据看就更清晰了。用算法来描述就是:给定一张表(假设表名叫作 t),t 表有字段(oid,period,amount,balance),对同一时期(period 字段的值相等)的金额(amount)按 oid 的顺序做累加求和操作,累加的结果放到 balance 字段。

结合数据来看,在原始数据中,当 oid = 1 时,amount = 3500.00,由于此时只有一条记录,所以 balance = 3500.00 ;当 oid = 2 时,amount = 5100.00,balance = 3500.00 + 5100.00 = 8600.00;同理,当 oid = 3 时,balance = 3500.00 + 5100.00 + 10000.00 = 18600.00 。

我们通过自关联来实现累计求和的结果,关联的条件可以这么写 t as t1 INNER JOIN t as t2 ON t2.period = t1.period AND t2.oid <= t1.oid。其中,t1 是主表,用来限定 t2 可以累加的数据的范围。比如,当 t1.oid = 5 时,t2.oid 只能是(4,5),对应的 balance 的计算过程就是 2560.00(t2.oid = 4 时的 amount) + 4700.00(t2.oid = 5 时的 amount) 。

完整的 SQL 就可以这么写:

WITH t AS

(SELECT

1 AS oid,

2009 AS period,

3500.00 AS amount,

0.00 AS balance

UNION

SELECT

2 AS oid,

2009 AS period,

5100.00 AS amount,

0.00 AS balance

UNION

SELECT

3 AS oid,

2009 AS period,

10000.00 AS amount,

0.00 AS balance

UNION

SELECT

4 AS oid,

2010 AS period,

2560.00 AS amount,

0.00 AS balance

UNION

SELECT

5 AS oid,

2010 AS period,

4700.00 AS amount,

0.00 AS balance)

# 上面的是造数据的SQL,下面这段才是核心实现SELECT

t1.oid,

t1.period,

t1.amount,

SUM(t2.amount) AS balance

FROM

t AS t1

LEFT JOIN t AS t2

ON t2.period = t1.period

AND t2.oid <= t1.oid

GROUP BY t1.oid,

t1.period,

t1.amount ;

看不惯自连接的写法可以换成标量子查询:

SELECT

oid,

period,

amount,

(SELECT

SUM(amount)

FROM

t

WHERE period = t1.period

AND oid <= t1.oid) AS balance

FROM

t AS t1

如果你的 MySQL 环境是 8.0 及其以上,可以尝试使用窗口函数。

SELECT

oid,

period,

amount,

SUM(amount) over (PARTITION BY period

ORDER BY oid) AS balance

FROM

t

实现累计求和差不多就是这些写法。如果你有不同的实现方式,欢迎在评论区留言,和大家分享你的思路。

来源:SQL实现

作者:zero

本文链接:https://my.lmcjl.com/post/15083.html

展开阅读全文

4 评论

留下您的评论.