比如mybatis要查询 一个主表a 一个子表b 我想把子表的fk_pro_id聚合到 主表里面去逗号分割,那么我需要怎么做呢?
方案一:SQL层面聚合(推荐)
1. SQL语句设计
使用数据库的聚合函数(如MySQL的GROUP_CONCAT
)直接在SQL中完成字段拼接:
sql
复制
SELECT
a.*,
GROUP_CONCAT(b.fk_pro_id) AS pro_ids
FROM
main_table a
LEFT JOIN
sub_table b ON a.id = b.fk_main_id
GROUP BY
a.id;
2. MyBatis映射配置
在Mapper XML中定义resultMap
,将聚合结果映射到Java对象的属性:
xml
复制
<resultMap id="MainResultMap" type="MainEntity">
<id property="id" column="id"/>
<!-- 其他主表字段映射 -->
<result property="proIds" column="pro_ids"/> <!-- 聚合字段 -->
</resultMap>
<select id="selectMainWithAggregatedSub" resultMap="MainResultMap">
SELECT
a.*,
GROUP_CONCAT(b.fk_pro_id) AS pro_ids
FROM
main_table a
LEFT JOIN
sub_table b ON a.id = b.fk_main_id
GROUP BY
a.id;
</select>
3. Java实体类定义
java
复制
public class MainEntity {
private Long id;
private String proIds; // 逗号分隔的子表ID集合
// 其他字段及getter/setter
}
方案二:MyBatis嵌套查询 + Java处理
1. 主查询获取主表数据
xml
复制
<select id="selectMainList" resultType="MainEntity">
SELECT * FROM main_table;
</select>
2. 子查询获取关联子表数据
xml
复制
<select id="selectSubByMainId" resultType="String">
SELECT fk_pro_id FROM sub_table WHERE fk_main_id = #{mainId}
</select>
3. Java代码拼接
在Service层通过循环调用子查询,将结果拼接为逗号分隔字符串:
java
复制
List<MainEntity> mainList = mainMapper.selectMainList();
mainList.forEach(main -> {
List<String> subIds = subMapper.selectSubByMainId(main.getId());
main.setProIds(String.join(",", subIds));
});
方案对比与建议
推荐场景:
方案一:数据量较大、对性能敏感、数据库支持聚合函数。
方案二:需要动态拼接逻辑、无法使用数据库聚合函数。
扩展优化
去重处理
在SQL聚合时添加DISTINCT
关键字避免重复:sql
复制
GROUP_CONCAT(DISTINCT b.fk_pro_id)
排序控制
指定子表数据的聚合顺序:sql
复制
GROUP_CONCAT(b.fk_pro_id ORDER BY b.create_time DESC)
分页兼容性
若需分页,建议在SQL聚合后通过LIMIT
和OFFSET
实现,避免嵌套查询导致分页失效。数据库兼容性
若使用非MySQL数据库(如Oracle),需替换为等效函数(如LISTAGG
)。