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
实现累计求和差不多就是这些写法。如果你有不同的实现方式,欢迎在评论区留言,和大家分享你的思路。
- 国内首个二代基因测序 FPGA 加速方案-背后的技术
- Java基础04 封装与接口
- Maven那点事儿(Eclipse版)
- 【Spring开发】—— Spring注入静态变量
- java判断list为空
- Java基础01 从HelloWorld到面向对象
- Java基础02 方法与数据成员
- 【Spring实战】—— 13 AspectJ注解切面
- EasyUI日期选择框
- Java基础03 构造器与方法重载
- web.xml is missing and <failOnMissingWebXml> is set to true
- 【Spring实战】—— 11 通过AOP为特定的类引入新的功能
- 使用Maven创建web项目
- 纸上谈兵: 树, 二叉树, 二叉搜索树
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- Lua的OS库时间函数
- wordpress上传图片无法显示的几种解决方法
- 交换二维数组
- 每天手撕一道算法-53. 最大子序和
- 基于 HTTP Header 传输签名参数
- 【原创】Java并发编程系列32 | 阻塞队列(下)
- 深入理解swap交换分区理解及扩存
- client-go 之 Reflector 源码分析
- Vue.js点击按钮弹出隐藏菜单的几种方式
- 【Vue.js】Vue.js组件库Element中的单选框、多选框、输入框和计数器
- 【Vue.js】Vue.js组件库Element的基础用法
- 常见的图像处理技术
- docker浅入深出续
- 【21期】你能说说Java中Comparable和Comparator的区别吗
- 昨天晚上熬夜整理的Java注解相关学习笔记