Stream 实现 Mysql中 sum case when
近日项目里面有个新需求,一个列表原先是通过sql语句groupBy分组得到的集合。但现在由于业务需求变动,结果集的某个状态需要动态生成,再根据这个状态进行求和,所以就不能使用sql直接查询出结果,需要在程序里面处理。
例如下面的例子,这种集合分组操作首先想到的就是使用Stream的groupBy来处理
由于是多字段分组,且还有根据不同条件求和,比较少用到。所以还是值得记录一下,大家对于这种业务如果还有更优雅的实现方式,也请评论区指点一下,感谢😘
SQL语句的原型:
大概的业务就是:根据 learn_state 状态来判断相加 course_credit字段的和 得到 gainCredit,在判断 gainCredit 是否大于等于moduleLowestCredit,得到 state
SELECT xrm.module_name moduleName, xrm.module_lowest_credit moduleLowestCredit, xrm.module_center_lowest_credit moduleCenterLowestCredit, sum( CASE WHEN xsc.learn_state = '4' THEN xcm.course_credit ELSE 0 END ) gainCredit, CASE WHEN sum( CASE WHEN xsc.learn_state = '4' THEN xcm.course_credit ELSE 0 END )>= xrm.module_lowest_credit THEN '已满足毕业条件' ELSE '未满足毕业条件' END state FROM table WHERE GROUP BY xrm.module_name, xrm.module_lowest_credit, xrm.module_center_lowest_credit
通过 Stream 实现
通过程序实现就需要把原先sql分组的数据都查询出来,不进行分组。如下例子:
得到所有待分组的数据,通过 stream 进行分组 。
@Test public void testStreamGroupBySum(){ // 要分组的数据 List<Map<String, Object>> courseDetail = new ArrayList<>(); Map<String, Object> testMap1 = new HashMap<>(); testMap1.put("moduleName", "公共基础课"); testMap1.put("moduleLowestCredit", "7"); testMap1.put("moduleCenterLowestCredit", "7"); testMap1.put("gainCredit", "3"); testMap1.put("learnState", "1"); courseDetail.add(testMap1); Map<String, Object> testMap2 = new HashMap<>(); testMap2.put("moduleName", "公共基础课"); testMap2.put("moduleLowestCredit", "7"); testMap2.put("moduleCenterLowestCredit", "7"); testMap2.put("gainCredit", "3"); testMap2.put("learnState", "4"); courseDetail.add(testMap2); Map<String, Object> testMap3 = new HashMap<>(); testMap3.put("moduleName", "公共英语课"); testMap3.put("moduleLowestCredit", "4"); testMap3.put("moduleCenterLowestCredit", "3"); testMap3.put("gainCredit", "4"); testMap3.put("learnState", "4"); courseDetail.add(testMap3); Map<String, Object> testMap4 = new HashMap<>(); testMap4.put("moduleName", "公共英语课"); testMap4.put("moduleLowestCredit", "4"); testMap4.put("moduleCenterLowestCredit", "3"); testMap4.put("gainCredit", "2"); testMap4.put("learnState", "4"); courseDetail.add(testMap4); // 多个字段分组统计处理 Map<String, List<Map<String, Object>>> collectMap = courseDetail.stream().collect(Collectors.groupingBy(d -> d.get("moduleName") + "_" + d.get("moduleLowestCredit")+ "_" + d.get("moduleCenterLowestCredit"),Collectors.toList())); // 得到分组后的集合 List<Map<String, Object>> newCourseDetail = collectMap.keySet().stream().map(key -> { Map<String, Object> pointMap = new HashMap<>(); String[] temp = key.split("_"); pointMap.put("moduleName", temp[0]); pointMap.put("moduleLowestCredit", temp[1]); pointMap.put("moduleCenterLowestCredit", temp[2]); List<Map<String, Object>> collectList = collectMap.get(key); if (CollectionUtil.isNotEmpty(collectList)) { int tempCredit = 0; for (Map<String, Object> map : collectList) { // 当条件是4时,相加分数 if ("4".equals(String.valueOf(map.get("learnState"))) && StrUtil.isNotBlank(String.valueOf(map.get("gainCredit")))) { tempCredit += Integer.parseInt(String.valueOf(map.get("gainCredit"))); } } pointMap.put("gainCredit", tempCredit); pointMap.put("state", tempCredit >= Integer.parseInt(temp[1]) ? "已满足毕业条件" : "未满足毕业条件"); } return pointMap; }).collect(Collectors.toList()); System.out.print(courseDetail); System.out.print(newCourseDetail); }
输出结果
从输出的结果可以看出,已经得到了和原先sql一致的的结果集了。
courseDetail: [{ moduleLowestCredit = 7, gainCredit = 3, moduleName = 公共基础课, learnState = 1, moduleCenterLowestCredit = 7 }, { moduleLowestCredit = 7, gainCredit = 3, moduleName = 公共基础课, learnState = 4, moduleCenterLowestCredit = 7 }, { moduleLowestCredit = 4, gainCredit = 4, moduleName = 公共英语课, learnState = 4, moduleCenterLowestCredit = 3 }, { moduleLowestCredit = 4, gainCredit = 2, moduleName = 公共英语课, learnState = 4, moduleCenterLowestCredit = 3 }] newCourseDetail: [{ moduleLowestCredit = 4, gainCredit = 6, moduleName = 公共英语课, state = 已满足毕业条件, moduleCenterLowestCredit = 3 }, { moduleLowestCredit = 7, gainCredit = 3, moduleName = 公共基础课, state = 未满足毕业条件, moduleCenterLowestCredit = 7 }]
总结
好了,以上就是本文的全部内容了,感谢大家的阅读。
本文通过一次实际项目案例,记录了使用 stream的多字段groupBy 来实现类似 mysql 中 sum、case when groupBy分组等语法。
#java后端##程序员#