多级目录SQL分层查询

需求:有多级目录,而目录的层级是不固定的,如下图所示:

数据结构:

sql语句:

sql 复制代码
<select id="getList" resultType="com.hikvision.idatafusion.dhidata.bean.vo.knowledgebase.KnowledgeBaseTypeTreeVo">
    with recursive tree as(
        select distinct kbt.id, kbt.type_name, kbt.type_sort, kbt.parent_id, 1 as type_level,
               kbt.id::text as id_path, kbt.type_name::text as type_name_path, kbt.type_sort::text as type_sort_path
        from knowledge_base_type kbt
        <if test="excludeNoDataType">
            join knowledge_base kb on kb.delete_flag = 0 and kb.type_id_list <![CDATA[&&]]> array[kbt.id]::int8[]
                    and kb.publish_state = '1'
        </if>
        where kbt.delete_flag = 0
        union
        select tree.id, tree.type_name, tree.type_sort, parent.parent_id, tree.type_level + 1 as type_level,
            concat(parent.id, '/', tree.id_path) as id_path,
            concat(parent.type_name, '/', tree.type_name_path) as type_name_path,
            concat(parent.type_sort, '/', tree.type_sort_path) as type_sort_path
        from tree
        join knowledge_base_type parent on parent.delete_flag = 0 and parent.id = tree.parent_id
    )
    select id, type_name, type_sort, type_level, id_path, type_name_path, type_sort_path
    from (
        select *,  ROW_NUMBER() OVER (PARTITION BY id ORDER BY type_level desc) AS rn from tree
    ) t
    where t.rn = 1
</select>

业务处理 :

java 复制代码
/**
 * 是否排除没有数据的分类
 */
@Override
public List<KnowledgeBaseTypeTreeVo> getList(boolean excludeNoDataType) {
    KnowledgeBaseTypeQueryDto knowledgeBaseTypeQueryDto = new KnowledgeBaseTypeQueryDto();
    knowledgeBaseTypeQueryDto.setExcludeNoDataType(excludeNoDataType);
    List<KnowledgeBaseTypeTreeVo> knowledgeBaseTypeTreeVoList  = knowledgeBaseTypeDao.getList(knowledgeBaseTypeQueryDto);
    // 对分类进行分层、排序
    Map<Long, KnowledgeBaseTypeTreeVo> firstLevelMap = new HashMap<>(); // 一级分类
    for (KnowledgeBaseTypeTreeVo knowledgeBaseType : knowledgeBaseTypeTreeVoList) {
        String[] idPath = knowledgeBaseType.getIdPath().split("/");
        // 生成一级分类
        long firstLevelId = Long.parseLong(idPath[0]);
        if(!firstLevelMap.containsKey(firstLevelId)) {
            KnowledgeBaseTypeTreeVo firstLevel = new KnowledgeBaseTypeTreeVo();
            firstLevel.setId(firstLevelId);
            firstLevel.setTypeName(knowledgeBaseType.getTypeNamePath().split("/")[0]);
            firstLevel.setTypeSort(Integer.parseInt(knowledgeBaseType.getTypeSortPath().split("/")[0]));
            firstLevel.setParentId(knowledgeBaseType.getParentId());
            firstLevelMap.put(firstLevelId, firstLevel);
        }
        // 遍历生成二级、三级...分类
        KnowledgeBaseTypeTreeVo firstLevel = firstLevelMap.get(firstLevelId); // 一级
        Map<Long, KnowledgeBaseTypeTreeVo> childrenMap = firstLevel.getChildrenMap();
        for (int i = 1; i < idPath.length; i++) { // 从二级开始遍历
            long typeId = Integer.parseInt(idPath[i]);
            if(!childrenMap.containsKey(typeId)) {
                KnowledgeBaseTypeTreeVo treeVo = new KnowledgeBaseTypeTreeVo();
                treeVo.setId(typeId);
                treeVo.setTypeName(knowledgeBaseType.getTypeNamePath().split("/")[i]);
                treeVo.setTypeSort(Integer.parseInt(knowledgeBaseType.getTypeSortPath().split("/")[i]));
                treeVo.setParentId((long) Integer.parseInt(idPath[i-1]));
                childrenMap.put(typeId, treeVo);
            }
            childrenMap = childrenMap.get(typeId).getChildrenMap(); // 下一级
        }
        // 排序
        for(KnowledgeBaseTypeTreeVo firstKnowledgeBaseType : firstLevelMap.values()) {
            this.sortChildren(firstKnowledgeBaseType);
        }
        knowledgeBaseType.setChildrenMap(firstLevelMap);
    }
    // 结果处理后返回
    List<KnowledgeBaseTypeTreeVo> knowledgeBaseTypeTreeList = firstLevelMap.values().stream().collect(Collectors.toList());
    return knowledgeBaseTypeTreeList;
}

/*
* 分类按TypeSort倒序
* */
private void sortChildren(KnowledgeBaseTypeTreeVo treeVo) {
    if(MapUtils.isEmpty(treeVo.getChildrenMap())) {
        return;
    }
    treeVo.setChildren(treeVo.getChildrenMap().values().stream().
            sorted(Comparator.comparingInt(KnowledgeBaseTypeTreeVo::getTypeSort).reversed()).collect(Collectors.toList()));
    for(KnowledgeBaseTypeTreeVo child: treeVo.getChildrenMap().values()) {
        sortChildren(child);
    }
}

返回数据实体类:

java 复制代码
@Data
@ToString
@EqualsAndHashCode(callSuper = false)
public class KnowledgeBaseTypeTreeVo implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "ID")
    private Long id;

    @ApiModelProperty(value = "类型名称")
    private String typeName;

    @ApiModelProperty(value = "序号,排序")
    private Integer typeSort;

    @ApiModelProperty(value = "父节点ID")
    public Long parentId;

    @ApiModelProperty(value = "分类层级")
    private Integer typeLevel;

    @ApiModelProperty(value = "分类ID层级路径")
    private String idPath;

    @ApiModelProperty(value = "分类名称层级路径")
    private String typeNamePath;

    @ApiModelProperty(value = "分类排序层级路径")
    private String typeSortPath;

    @ApiModelProperty(value = "子分类")
    private List<KnowledgeBaseTypeTreeVo> children = new ArrayList();

    @ApiModelProperty(value = "分类")
    private Map<Long, KnowledgeBaseTypeTreeVo> childrenMap = new HashMap<>();
}
相关推荐
好看资源平台4 分钟前
Spring 全家桶使用教程 —— 后端开发从入门到精通
java·数据库·spring
Satan7128 分钟前
【Spring】Spring Aop基础入门
java·开发语言·jvm
这河里吗l16 分钟前
Java每日面试题(JVM)(day15)
java·开发语言·jvm·笔记·后端
white__ice18 分钟前
2024.9.27
java
robot_大菜鸟33 分钟前
Powerbi -l9-异常数据的处理
android·java·powerbi
江南一点雨35 分钟前
又一家培训机构即将倒闭!打工人讨薪无果,想报名的小伙伴擦亮眼睛~
java·程序员
Satan7121 小时前
【Java】JVM基本组成
java·开发语言·jvm
@月落1 小时前
获取douyin商品详情:API接口的力量
java·前端·数据库
hakesashou1 小时前
python命令行怎么换行
java·前端·python
yang-23071 小时前
ElasticSearch安装分词器与整合SpringBoot
java·spring boot·elasticsearch·jenkins