Java MySQL递归子级父级,构建树结构

Posted 符华-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java MySQL递归子级父级,构建树结构相关的知识,希望对你有一定的参考价值。

记录一下

目录



🥩 mysql递归子级、父级

🌭 递归所有子级

🥓 方式一:

注意:此方式只适用 id、parent_id 是数字或纯数字的字符串,否则不生效。

SELECT id,`name`
FROM (SELECT id,parent_id,`name` FROM sys_dept where parent_id != '0') a,
     (SELECT @pv :=#parentId) b
WHERE (FIND_IN_SET(parent_id,@pv) != '0' AND @pv := concat(@pv, ',', id))

🥓 方式二:

注意:这个方法纯数字没问题,但是其他字符串不知道为什么有的时候可以,有的时候又不能获取到全部子级

之前一开始我验证这个方法的时候,id是64位随机字符串,parentId也一样,验证的时候是没问题的;但是后面我为了写这篇文章我改了部门表的数据,id、parentId同样是随机字符串,就突然不行了。比如获取某个公司下面所有分公司、单位部门,总共有四级,其中一个分公司下的一个部门没有获取到,自然这个部门的子级也没获取到。但是当我 #parentId 传那个分公司的id时又能获取到这个部门和它的子级。这个部门是3级的,它的子级是4级,可是这个公司还有其他的3级4级啊,其他的都能获取到,就它不行,不知道是为啥。

SELECT id,`name`
FROM(
    SELECT id,`name`,IF(find_in_set(parent_id, @pv) != 'ROOT',@pv := concat(@pv, ',', id),'ROOT') AS childList
    FROM (SELECT id,parent_id,`name` FROM sys_dept) a, (SELECT @pv :=#parentId) b
) t3
WHERE childList != 'ROOT';

🥓 方式三:

这下是真的改良版了,经过多次数据更改测试,无论是纯数字还是随机字符串,都没问题

这里包括了本身

SELECT b.id,b.parent_id,b.name
FROM(
	SELECT @ids AS _ids,
	(SELECT @ids := GROUP_CONCAT(id) FROM sys_dept WHERE FIND_IN_SET(parent_id, @ids)) AS cids
	FROM sys_dept,(SELECT @ids := #parentId) b 
	WHERE @ids IS NOT NULL 
) a,sys_dept b 
WHERE FIND_IN_SET(b.id, a._ids) 
ORDER BY LEVEL,id

效果:



🍔 递归所有父级

🍗 方式一:

我们可以直接从上面递归子级的方式三中,拿这个sql进行更改,经测试也是没问题的。这个也同样包括了它本身。

SELECT b.id,b.parent_id,b.name
FROM(
	SELECT @ids AS _ids,
	(SELECT @ids := GROUP_CONCAT(parent_id) FROM sys_dept WHERE FIND_IN_SET(id, @ids)) AS cids
	FROM sys_dept,(SELECT @ids := #id) b 
	WHERE @ids IS NOT NULL 
) a,sys_dept b 
WHERE FIND_IN_SET(b.id, a._ids) 
ORDER BY LEVEL,id

效果:

🥩 Java递归子级、父级

🍚 递归子级列表

/**
 * 递归查询,获取子级列表(不包含本身)
 */
public List<SysDept> childIdList(String parentId)
    List<SysDept> resultList = new ArrayList<>();
    QueryWrapper<SysDept> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("parent_id",parentId);
    queryWrapper.select("id");
    List<SysDept> list = baseMapper.selectList(queryWrapper);
    for (SysDept dept : list) 
        resultList.addAll(childIdList(dept.getId()));
    
    list.addAll(resultList);
    return list;


🍜 递归父级列表

/**
 * 递归查询,获取父级列表(包含本身)
 */
public List<SysDept> parentIdList(String id)
	List<SysDept> resultList = new ArrayList<>();
	QueryWrapper<SysDept> queryWrapper = new QueryWrapper<>();
	queryWrapper.eq("id",id);
	queryWrapper.select("parent_id","name");
	List<SysDept> list = baseMapper.selectList(queryWrapper);
	for (SysDept dept : list) 
	    resultList.addAll(parentIdList(dept.getParentId()));
	
	list.addAll(resultList);
    return list;

🥩 TreeUtil 树结构构建工具

import cn.hutool.core.util.ReflectUtil;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 树结构构建工具类
 */
public class TreeUtil 

    /**
     * 根据反射获取属性值
     * @param t 实体对象
     * @param fieldName 属性名称
     */
    private static<T> Object getFieldValue(T t,String fieldName)
        Field field = ReflectUtil.getField(t.getClass(), fieldName);
        return ReflectUtil.getFieldValue(t, field);
    

    /**
     * 获取树结构(知道顶级节点的id的情况下用)
     * 比如部门列表,如果是管理员,那肯定是全部的数据,一般情况下,顶级节点的父级id都是0或ROOT,表示它是最顶级。
     * 管理员获得全部数据,这种情况下就知道顶级节点的id的值,所以parentId直接传0或ROOT。
     */
    public static<T> List<T> buildTreeIsRoot(List<T> list,String parentId) 
        List<T> root = buildTree(list, parentId);
        getChild(root, list);
        return root;
    

    /**
     * 获取树结构(parentId值不确定)
     * 除了顶级节点可以确定parentId的值,其他的都是不确定的。
     * 比如是部门经理,就只能看到自己部门和子部门的数据,构建的树结构也应该是只显示出本部门、子部门。
     */
    public static<T> List<T> buildTreeNotRoot(List<T> list) 
        List<T> sources = new ArrayList<>(list);
        List<T> result = new ArrayList<>();
        for (T t : sources) 
            String parentId = (String)getFieldValue(t,"parentId");
            List<T> root = buildTree(list, parentId);
            getChild(root, list);
            result.addAll(root);
        
        return result;
    

    /**
     * 获取树结构
     * @param list 数据
     * @param pId 父级id
     */
    private static<T> List<T> buildTree(List<T> list,String pId)
        List<T> root= new ArrayList<>();
        Iterator<T> it = list.iterator();
        while (it.hasNext()) 
            T t = it.next();
            String parentId = (String)getFieldValue(t,"parentId");
            if (parentId.equals(pId)) 
                root.add(t);
                it.remove();
            
        
        return root;
    

    /**
     * 递归子节点
     */
    public static<T> void getChild(List<T> root,List<T> list)
        try 
            for (T nav : root) 
                String id = (String)getFieldValue(nav,"id");
                List<T> childList = buildTree(list, id);
                getChild(childList, list);
                Field child = ReflectUtil.getField(nav.getClass(), "children");
                child.set(nav,childList);
            
        catch (Exception e)
            e.printStackTrace();
        
    

以上是关于Java MySQL递归子级父级,构建树结构的主要内容,如果未能解决你的问题,请参考以下文章

完整的二叉树交换子级和父级错误

Oracle递归查询(查询当前记录所有父级或子级)

MySQL递归查询,实现上下级联查,父子级查询

如何使引导树视图从父级折叠到子级?

SQL递归查询所有子节点

如何为不是直接父级而是父级父级的嵌套元素设置百分比宽度?