多级目录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<>();
}
相关推荐
非 白13 分钟前
【Java】单例模式
java·笔记·单例模式
RainbowSea24 分钟前
9-1. MySQL 性能分析工具的使用——last\_query\_cost,慢查询日志
数据库·sql·mysql
IDRSolutions_CN27 分钟前
如何在 PDF 文件中嵌入自定义数据
java·经验分享·pdf·软件工程·团队开发
_风中无我。33 分钟前
Spring的过滤器获取请求体中JSON参数,同时解决Controller获取不到请求体参数的问题。
java·spring·json
bing_15843 分钟前
Spring Boot 中为什么 需要限流、降级和熔断?
java
ccm031 小时前
高效开发助手:深入了解Hutool工具库
java·g工具库
雪落南城1 小时前
【Maven】maven加载不到包
java·maven
tekin3 小时前
Go、Java、Python、C/C++、PHP、Rust 语言全方位对比分析
java·c++·golang·编程语言对比·python 语言·php 语言·编程适用场景
李长渊哦4 小时前
Java 虚拟机(JVM)方法区详解
java·开发语言·jvm
陌殇殇5 小时前
002 SpringCloudAlibaba整合 - Feign远程调用、Loadbalancer负载均衡
java·spring cloud·微服务