多级目录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<>();
}
相关推荐
SUPER52662 小时前
FastApi项目启动失败 got an unexpected keyword argument ‘loop_factory‘
java·服务器·前端
咕噜咕噜啦啦3 小时前
Eclipse集成开发环境的使用
java·ide·eclipse
养生技术人4 小时前
Oracle OCP认证考试题目详解082系列第57题
运维·数据库·sql·oracle·开闭原则
光军oi5 小时前
全栈开发杂谈————关于websocket若干问题的大讨论
java·websocket·apache
weixin_419658315 小时前
Spring 的统一功能
java·后端·spring
小许学java6 小时前
Spring AI-流式编程
java·后端·spring·sse·spring ai
haogexiaole6 小时前
Java高并发常见架构、处理方式、api调优
java·开发语言·架构
EnCi Zheng7 小时前
@ResponseStatus 注解详解
java·spring boot·后端
wdfk_prog7 小时前
闹钟定时器(Alarm Timer)初始化:构建可挂起的定时器基础框架
java·linux·数据库
怎么没有名字注册了啊7 小时前
C++后台进程
java·c++·算法