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后端##程序员#
全部评论

相关推荐

大方的大熊猫准备进厂:1.教育背景:你希望从事什么专业的工作你的主修课就是什么;成绩优秀是你应该做的,没什么可描述的,成绩不优秀也许人家在大学忙着创业呢?(成绩优秀不一定是好事,只能说明多元化的大学你上成了高中,没有真正上明白大学,反而体现了你死板,不爱社交,没有别的突出能力) 2.实践经历:你想表达的意思没有说清楚。你是说你会个性化服务,还是你有实习经历。如果没有带来,经济收益,表彰,更好的发展前景,那你还不如说说提升了自己哪些技能。你说有人给你送锦旗我都能明白你优秀,但是你说你会xxxx,你说这话谁信,证据呢。 3.入伍经历:你描述的就是你的工作职责或者你应该做的,并没有体现出来你把这个事情做好了,而且入伍经历并不能证明你能干好你要应聘的工作,不如只写经历其余所有内容都不写。 4.荣誉技能:重点突出一下,但不要过多描述,这些荣誉的含金量懂得都懂。 重点:你要应聘什么工作(具体岗位,实习生不具体),你的期望薪资
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务