多条记录求和问题

下面语句sql server与oracle均适用:

select sum(A+B+C)
AS D
from ...
where ...
group by ...

当有多条记录需要**合并计算**时,核心思想是:**按某个分组键(如类别、部门、日期等)将相同组的记录聚合起来,并对数值字段进行累加或其他统计操作(如计数、平均值等)**。 你提到“怎么合并计算”,下面我以一个典型场景为例,详细说明如何用 Java 实现多条记录的合并与汇总,包括使用 `Stream` + `groupingBy` 的现代写法。 --- ## 🎯 场景设定 假设我们有如下数据类: ```java public class LiquidReportChart { private String cellValue1; // 分组字段,如 "部门" private String cellValue2; // 数值1,如收入 private String cellValue3; // 数值2,如支出 private String cellValue4; // 数值3,如利润 private String cellValue5; // 数值4,如人数(整数) // 构造函数、getter/setter 略 } ``` 我们有一堆这样的对象(`List<LiquidReportChart> list`),现在要: ✅ **把 `cellValue1` 相同的所有记录合并成一条:** - `cellValue2~4`:转为 `BigDecimal` 并求和 - `cellValue5`:转为整数并求和 --- ## ✅ 解决方案:使用 Stream 分组 + reduce ```java import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; // 工具方法:安全解析字符串为 BigDecimal private BigDecimal parse(String s) { if (s == null || s.trim().isEmpty()) return BigDecimal.ZERO; try { return new BigDecimal(s.trim()); } catch (NumberFormatException e) { return BigDecimal.ZERO; } } // 安全解析为 int private int parseInt(String s) { if (s == null || s.trim().isEmpty()) return 0; try { return Integer.parseInt(s.trim()); } catch (NumberFormatException e) { return 0; } } ``` ### 🔧 合并计算主逻辑 ```java Map<String, BigDecimal[]> merged = list.stream() .collect(Collectors.groupingBy( LiquidReportChart::getCellValue1, // 按 cellValue1 分组 Collectors.reducing( new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO}, chart -> new BigDecimal[]{ parse(chart.getCellValue2()), parse(chart.getCellValue3()), parse(chart.getCellValue4()), BigDecimal.valueOf(parseInt(chart.getCellValue5())) // 转为 BigDecimal 统一处理 }, (a, b) -> new BigDecimal[]{ a[0].add(b[0]), // 收入相加 a[1].add(b[1]), // 支出相加 a[2].add(b[2]), // 利润相加 a[3].add(b[3]) // 人数相加 } ) )); ``` ### ✅ 结果示例 原始数据: | cellValue1 | cellValue2 | cellValue3 | cellValue4 | cellValue5 | |-----------|------------|------------|------------|------------| | 销售部 | 100.5 | 60.2 | 40.3 | 5 | | 销售部 | 200.0 | 80.0 | 120.0 | 3 | | 财务部 | 50.0 | 30.0 | 20.0 | 2 | 合并后结果: ```java merged = { "销售部" -> [300.5, 140.2, 160.3, 8], "财务部" -> [50.0, 30.0, 20.0, 2] } ``` --- ## ✅ 如何还原成对象列表?(可选) 如果你希望把合并后的结果再封装回 `LiquidReportChart` 或新类型: ```java List<LiquidReportChart> result = merged.entrySet().stream() .map(entry -> { String key = entry.getKey(); BigDecimal[] sums = entry.getValue(); return new LiquidReportChart( key, sums[0].toString(), sums[1].toString(), sums[2].toString(), sums[3].toBigInteger().toString() ); }) .collect(Collectors.toList()); ``` 这样你就得到了一个“每组一条”的精简报表数据。 --- ## ✅ 更优雅的方式:使用自定义聚合类(推荐) 避免使用数组,提升可读性和维护性: ```java public class Summary { private BigDecimal income; private BigDecimal expense; private BigDecimal profit; private int count; public Summary() { this.income = BigDecimal.ZERO; this.expense = BigDecimal.ZERO; this.profit = BigDecimal.ZERO; this.count = 0; } public Summary add(LiquidReportChart chart) { return new Summary( this.income.add(parse(chart.getCellValue2())), this.expense.add(parse(chart.getCellValue3())), this.profit.add(parse(chart.getCellValue4())), this.count + parseInt(chart.getCellValue5()) ); } // 全参构造 + getter } ``` 然后合并: ```java Map<String, Summary> summaryMap = list.stream() .collect(Collectors.groupingBy( LiquidReportChart::getCellValue1, Collectors.reducing(new Summary(), Summary::new, Summary::merge) )); ``` > ⚠️ 注意:你需要实现 `merge(Summary a, Summary b)` 方法来支持合并两个 `Summary` 对象。 --- ## ✅ 总结:多条记录合并计算的关键步骤 | 步骤 | 操作 | |------|------| | 1️⃣ 分组 | 使用 `.groupingBy(keyExtractor)` 按共同字段分组 | | 2️⃣ 映射 | 将每条记录转换为可累加的数据结构(如数组或对象) | | 3️⃣ 合并 | 提供 `BinaryOperator<T>` 定义如何将两个值相加 | | 4️⃣ 初始化 | 提供初始值(通常是零值)防止空指针 | | 5️⃣ 转换(可选) | 将 Map 结果转为 List 或其他格式用于输出 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值