Java8中使用groupBy实现集合的分组,并根据某一条件进行分组

本文介绍Java8中使用Stream API结合Collectors.groupingBy()方法进行集合分组的实战案例,通过具体的学生信息集合,展示了如何按学生姓名进行分组并输出结果。

一、简介:

Java8中的groupBy实现集合的分组,类似Mysql的group by分组功能,注意得到的结果是一个map

二、代码测试案例:

package demo;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import entity.Student;

/**
* @author :zkx
* @createtime :2020年3月17日 下午4:46:31
* @description:
*/

public class Test03 {
	
	public static void main(String[] args){
		
		List<Student> list = new ArrayList<>();
		
		Student Student1 = new Student("1", "张三", "10");
		Student Student2 = new Student("2", "张三", "11");
		Student Student3 = new Student("3", "张三", "12");
		Student Student4 = new Student("4", "李四", "13");
		Student Student5 = new Student("5", "李四", "14");
		Student Student6 = new Student("6", "李四", "15");
		Student Student7 = new Student("7", "王五", "16");
		Student Student8 = new Student("8", "王五", "17");
		Student Student9 = new Student("9", "王五", "18");
		list.add(Student1);
		list.add(Student2);
		list.add(Student3);
		list.add(Student4);
		list.add(Student5);
		list.add(Student6);
		list.add(Student7);
		list.add(Student8);
		list.add(Student9);
		
		// 根据学生的名字Name进行分组
		Map<String,List<Student>> StudentGroupMap = list.stream().
				collect(Collectors.groupingBy(Student::getName));
		
		// 分组结果
		System.out.println("分组后的数据:" + StudentGroupMap);
		System.out.println();
		
		// 循环查看分组后对应的的数据信息
		Set<String> keySet = StudentGroupMap.keySet();
		keySet.forEach((key)->{
			System.out.println(key);
			StudentGroupMap.get(key).
				forEach((Student)->
				System.out.println(Student));
		});
	}


}

三、效果图如下:

在这里插入图片描述

<think>我们正在处理个关于MyBatis动态SQL的问题,用户希望根据条件动态使用GROUP BY对两个字段进行分组。这意味着在某些情况下可能只按个字段分组,在另些情况下按两个字段分组。解决方案:我们可以使用MyBatis的动态SQL标签(如<choose>,<when>, <otherwise>)来构建动态的GROUPBY子句。步骤:1.在Mapper的XML文件中,我们可以使用<choose>标签来根据条件选择不同的分组字段。2.注意:在GROUP BY子句中,我们需要根据条件动态拼接字段,可以使用<if>标签或者<choose>标签。示例场景:假设我们有个订单表(order),我们想根据条件动态分组:-当条件type=1时,按字段field1分组-当条件type=2时,按字段field1和field2分组但是用户要求的是“两个字段”,这里我们假设用户的意思是:有时按个字段分组(比如field1),有时按两个字段分组(field1和field2)。注意,动态SQL允许我们灵活构建。另种理解:用户可能希望根据条件选择分组字段的数量(个或两个),或者根据不同的条件选择不同的分组字段组合。我们假设用户传递的参数中有个字段(比如groupByField2)用于判断是否需要按第二个字段分组。如果groupByField2为true,则按两个字段分组;否则按个字段分组。示例SQL映射: ```xml<selectid="selectOrders" resultType="Order">SELECTfield1,field2, SUM(amount) astotalAmountFROM order<where><!--其他条件--></where>GROUP BYfield1<iftest="groupByField2!= nulland groupByField2">,field2</if> </select>```但是,上面的写法在GROUPBY后面直接跟了个字段,然后通过<if>动态添加另个字段。注意:在SQL中,GROUP BY子句的字段之间用逗号分隔,所以当需要添加第二个字段时,我们在前面加逗号。但是这样写如果第个字段后面直接跟逗号然后第二个字段,当条件不满足时,GROUPBY后面只有个字段,这是正确的。然而,如果我们需要根据不同的条件选择完全不同的分组字段(不仅仅是追加),那么我们可以使用<choose>。例如,根据不同的类型选择分组字段:```xml<select id="selectOrders"resultType="Order">SELECT field1,field2, field3,SUM(amount)as totalAmountFROMorder<where><!--其他条件 --></where>GROUPBY<choose><when test="type==1">field1</when><when test="type==2">field1,field2</when><otherwise>field3</otherwise></choose> </select>```注意:在<choose>内部,每个分支中我们写完整的GROUP BY表达式(可以是个或多个字段,用逗号分隔)。但是,用户要求的是“两个字段”,所以我们主要关注如何动态地按个或两个字段分组。推荐第种方式:当基本分组字段固定,只是可能追加另个字段时,使用<if>追加。这种方式更简洁。第二种方式:当分组字段完全变化时,使用<choose>。根据用户的问题描述,他可能想要的是第种情况:固定个字段,然后根据条件决定是否追加第二个字段。因此,我们给出第种方式的示例。但是,请注意:在GROUPBY子句中,如果使用<if>来动态追加字段,要确保第个字段是始终存在的,然后根据条件决定是否添加逗号和第二个字段。这样写是安全的,因为当条件不满足时,GROUPBY后面只有个字段。另外,还有种情况:用户可能希望根据条件选择不同的字段组合,而不定是追加。所以我们需要根据用户的实际需求来设计。但问题中只提到“两个字段”,所以我们可以假设用户的基本需求是:有时按个字段分组,有时按两个字段分组。如果用户需要动态选择多个字段(不固定是追加),那么使用<choose>更灵活。现在,我们按照用户的问题,给出个通用的示例,假设用户有条件参数`groupBySecondField`(布尔类型)来决定是否按第二个字段分组。示例代码: ```xml<selectid="selectByCondition"resultMap="yourResultMap">SELECT field1,field2, COUNT(*)as countFROM your_tableGROUPBY field1<if test="groupBySecondField !=null andgroupBySecondField">, field2</if></select> ```或者,如果用户希望根据条件选择两个不同的字段(不是追加,而是两个独立的字段选择),那么我们可以这样: ```xml<selectid="selectByCondition"resultMap="yourResultMap">SELECT<choose><whentest="condition =='case1'">field1</when><otherwise>field2</otherwise></choose>as groupField,COUNT(*) ascountFROMyour_tableGROUP BY<choose><whentest="condition =='case1'">field1</when><otherwise>field2</otherwise></choose> </select>```但是,这个例子中只按个字段分组,只是这个字段根据条件变化。如果用户需要同时按两个字段分组,但这两个字段的组合根据条件变化,那么就需要使用<choose>来列出不同的组合。由于问题描述是“动态使用GROUP BY对两个字段进行分组”,我们理解为:分组字段可能是两个字段,也可能是个字段(即第二个字段可选)。所以我们采用第种追加的方式。注意:在动态SQL中,逗号的处理要小心。我们在第个字段后面不加逗号,然后在<if>里面写逗号加第二个字段,这样当条件满足时,就会变成:GROUPBY field1,field2;当条件不满足时,就是GROUP BYfield1。如果用户需要动态选择多个字段组合(例如,可能按field1和field2,也可能按field3和field4),那么就需要使用<choose>来分别写不同的分组组合。总结:根据用户的需求描述,我们推荐使用种方式(追加字段)来实现动态分组。另外,如果用户需要动态选择多个分组字段(不仅仅是两个),也可以使用<foreach>标签,但需要提前将分组字段放入集合中。不过,这个问题中用户明确要求两个字段,所以我们不展开。因此,我们给出第种方式的示例。在Mapper接口中定义方法:```javaList<YourResult>selectByCondition(@Param("groupBySecondField") BooleangroupBySecondField); ```在XML中: ```xml<selectid="selectByCondition"resultMap="yourResultMap">SELECT field1,field2, SUM(value) astotalFROMyour_tableGROUP BYfield1<iftest="groupBySecondField!= nulland groupBySecondField">,field2</if> </select>```注意:这里我们假设field1是始终要分组的字段,field2是根据条件决定是否追加的字段。如果用户希望两个字段都是可选的,那么就需要更复杂的逻辑。但根据问题,我们理解为“对两个字段进行分组”意味着在需要时同时使用两个字段分组,不需要时只用个字段(可能是其中个)。但问题没有明确,所以我们按照固定第个字段,可选第二个字段来处理。如果用户需要两个字段都是可选的,那么我们可以这样: ```xml<selectid="selectByCondition"resultMap="yourResultMap">SELECTfield1,field2,SUM(value) astotalFROMyour_tableGROUP BY<iftest="useField1 !=null anduseField1">field1</if><iftest="useField1 !=null anduseField1 anduseField2 !=null anduseField2">,</if><if test="useField2!= nulland useField2">field2</if></select> ```但是这样写有风险:如果两个字段都不选,那么GROUPBY后面就是空的,这是不允许的。所以我们需要确保至少有个字段。因此,我们可以使用<choose>来确保至少有分组字段: ```xml<selectid="selectByCondition"resultMap="yourResultMap">SELECTfield1,field2,SUM(value)as totalFROM your_tableGROUPBY<choose><when test="useField1!= nulland useField1and useField2!= nulland useField2">field1, field2</when><when test="useField1!= nulland useField1">field1</when><whentest="useField2 !=null anduseField2">field2</when><otherwise><!--默认分组字段,比如个常量,但这样可能不是用户想要的,所以最好避免,或者抛出异常?-->1</otherwise></choose></select> ```但是,这个需求可能超出了用户的问题范围。我们回到用户的问题,他要求的是“根据条件动态使用GROUP BY对两个字段进行分组”,所以我们理解为:在同分组需求中,有时按个字段分组(这个字段是固定的),有时按两个字段分组(同个字段和另个字段)。所以我们最初给出的第种方式(固定第个字段,根据条件追加第二个字段)应该是最符合的。因此,我们最终给出第种方式的示例。如果用户有更复杂的需求,可以再根据具体情况调整。注意:在动态SQL中,逗号的位置很重要,要避免出现语法错误(比如多余的逗号)。最后,我们生成相关问题。</think>在MyBatis中根据条件动态使用`GROUP BY`对两个字段进行分组,可以通过动态SQL标签(如`<if>`、`<choose>`)灵活拼接SQL语句。以下是具体实现方案: ### 解决方案 #### 1. 使用`<choose>`标签实现分支逻辑 当需要根据不同条件选择不同的分组字段组合时: ```xml <select id="selectWithDynamicGroupBy" resultType="YourResult"> SELECT field1, field2, COUNT(*) AS count FROM your_table <where> <!-- 其他查询条件 --> </where> GROUP BY <choose> <when test="condition == 'caseA'"> field1 <!-- 仅按field1分组 --> </when> <when test="condition == 'caseB'"> field1, field2 <!-- 同时按两个字段分组 --> </when> <otherwise> field2 <!-- 默认按field2分组 --> </otherwise> </choose> </select> ``` #### 2. 使用`<if>`标签动态追加字段 当始终包含第个字段,根据条件决定是否添加第二个字段时: ```xml <select id="selectWithDynamicGroupBy" resultType="YourResult"> SELECT field1, field2, SUM(value) AS total FROM your_table GROUP BY field1 <!-- 固定第个字段 --> <if test="needGroupByField2 != null and needGroupByField2"> , field2 <!-- 条件满足时追加第二个字段 --> </if> </select> ``` #### 3. 使用`<trim>`处理复杂场景 当分组字段数量和顺序动态变化时: ```xml <select id="selectWithDynamicGroupBy" resultType="YourResult"> SELECT field1, field2, field3, AVG(score) AS avg_score FROM your_table GROUP BY <trim prefixOverrides=","> <if test="includeField1">field1</if> <if test="includeField2">, field2</if> <if test="includeField3">, field3</if> </trim> </select> ``` ### 关键说明 1. **逗号处理**: - 在`<if>`标签中,第二个字段**必须包含逗号前缀**(如`, field2`),避免语法错误 - 使用`<trim prefixOverrides=",">`可自动移除多余的引导逗号 2. **参数传递**: Mapper接口需定义条件参数: ```java List<YourResult> selectWithDynamicGroupBy( @Param("condition") String condition, @Param("needGroupByField2") Boolean needGroupByField2 ); ``` 3. **注意事项**: - 确保`SELECT`子句中的字段与`GROUP BY`字段匹配 - 动态字段名需防止SQL注入(避免直接拼接用户输入) ### 示例场景 假设根据用户权限动态分组: - 管理员:按`department`和`team`分组 - 普通用户:仅按`department`分组 ```xml <select id="selectGroupedData" resultType="map"> SELECT department, team, COUNT(employee_id) AS headcount FROM employees GROUP BY department <if test="isAdmin != null and isAdmin"> , team <!-- 管理员追加team字段 --> </if> </select> ``` ### 相关问题 1. 如何在MyBatis中动态生成`ORDER BY`子句? 2. MyBatis动态SQL如何处理`IN`条件中的可变参数列表? 3. 使用MyBatis时如何防止动态SQL拼接导致的SQL注入风险? 4. 在动态`GROUP BY`场景下,如何优化查询性能? [^1]: 动态SQL配置可参考MyBatis官方文档的XML映射器章节。 [^2]: 复杂条件处理可结合OGNL表达式增强灵活性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Monika、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值