草庐IT

mysql根据父节点递归查询所有子节点,List转树形结构工具类

_Mervin_ 2023-09-05 原文

经常有业务需要递归查询MySQL树形结构某一节点的所有子节点,每次从网上扒拉找都得找半天,索性就自己总结一些自己遇到的比较好用的一些方法。

SQL方法一:

SELECT
    * 
FROM
    (
    SELECT
        t1.*,
    IF
        ( FIND_IN_SET( parent_id, @parent_ids ) > 0, @parent_ids := CONCAT( @parent_ids, ',', id ), '0' ) AS ischild 
    FROM
        ( SELECT * FROM blade_menu AS t WHERE t.is_deleted = 0 AND client_type = 'dianduyun_app' ORDER BY t.id ASC ) t1,
        ( SELECT @parent_ids := '1508255373140103170' ) t2 
    ) t3 
WHERE
    ischild != '0'


需要修改的地方

  • parent_id,改为你的父级id字段
  • blade_menu ,改为你的表名称
  • WHERE t.is_deleted = 0 ,改为你的查询条件
  • @parent_ids := ‘1508255373140103170’,值改为你要传入的父级id

执行结果


 

SQL方法二:

SELECT
    rd.* 
FROM
    ( SELECT * FROM fine_authority_object WHERE parentId IS NOT NULL AND is_deleted = 0 ) rd,
    ( SELECT @pid := '2342465874553522423' ) pd 
WHERE
    FIND_IN_SET( parentId, @pid ) > 0 
    AND @pid := concat( @pid, ',', id ) 

 

UNION
SELECT
    * 
FROM
    fine_authority_object 
WHERE
    FIND_IN_SET( id, @pid ) > 0;


需要修改的地方

  • fine_authority_object ,改为你的表名,以及后面的查询条件进行修改。
  • SELECT @pid := ‘2342465874553522423’ ,值改为你要传的父id的值
  • FIND_IN_SET( parentId, @pid ) ,parentId改为你的父级id字段名

备注:

  • 当前这条SQL是根据多个父节点查询所有子节点(包含自身)
  • 如果不想查询结果包含自身,去掉后边的union

执行结果示例

同方法二的例子:查询父区域下的所有子区域(包括4/5级)

SELECT
	rd.* 
FROM
	( SELECT * FROM sys_region WHERE pid IS NOT NULL ) rd,
	( SELECT @p_id := '19' ) pd 
WHERE
	FIND_IN_SET( pid, @p_id ) > 0 
	AND @p_id := concat( @p_id, ',', region_id ) 
CREATE TABLE `sys_region` (
  `region_id` bigint(20) NOT NULL COMMENT '主键',
  `pid` bigint(20) DEFAULT NULL COMMENT '父id',
  `region_name` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '名称',
  `region_code` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '编码',
  `type` tinyint(4) DEFAULT NULL COMMENT '类型',
  `remark` varchar(1000) COLLATE utf8_bin DEFAULT NULL COMMENT '备注',
  `del_flag` tinyint(4) DEFAULT NULL COMMENT '删除标记',
  `create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `longitude` decimal(10,6) DEFAULT NULL COMMENT '经度',
  `latitude` decimal(10,6) DEFAULT NULL COMMENT '纬度',
  PRIMARY KEY (`region_id`) USING BTREE,
  KEY `region_code_index` (`region_code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC COMMENT='行政区域';


 

 

Java List转树形结构


另外再分享一个将上面查询出来的list给转成树形结构的形式给前端返回的一个工具类。

 

 public static List<ReportTemplateVo> listToTree2(List<ReportTemplateVo> list) {
        List<ReportTemplateVo> tree = new ArrayList<>();
        for (ReportTemplateVo ReportTemplateVo : list) {
            //找到根节点
            if (ReportTemplateVo.getParentId().equals("reportlets")) {
                tree.add(findChildren(ReportTemplateVo, list));
            }
        }
        return tree;
    }

    /**
     * 查找ReportTemplateVo的子节点
     * @param ReportTemplateVo
     * @param list
     * @return
     */
    private static ReportTemplateVo findChildren(ReportTemplateVo ReportTemplateVo, List<ReportTemplateVo> list) {
        List<ReportTemplateVo> children = new ArrayList<>();
        for (ReportTemplateVo node : list) {
            if (node.getParentId().equals(ReportTemplateVo.getId())) {
                //递归调用
                children.add(findChildren(node, list));
            }
        }
        ReportTemplateVo.setChildren(children);
        return ReportTemplateVo;
    }



ReportTemplateVo实体:

public class ReportTemplateVo  {
    private static final long serialVersionUID = 1L;
    /**
     * 主键ID
     */
    private String id;

    /**
     * 父节点ID
     */
    private String parentId;

    /**
     * 子孙节点
     */
    private List<ReportTemplateVo> children;

    @ApiModelProperty("节点是否可以被选中")
    private Boolean disabled;

    /**
     * 节点名称
     */
    @ApiModelProperty("节点名称")
    private String title;


总结


这两种方法都可以查询到自己想要的数据。然后调用这个方法可以直接生成相应的树形结构,这种东西很常用,又懒得自己写, 所以勤记录,多做备份会省很多事儿,
 

有关mysql根据父节点递归查询所有子节点,List转树形结构工具类的更多相关文章

  1. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

    我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

  2. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  3. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  4. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  5. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  6. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  7. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  8. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  9. sql - 查询忽略时间戳日期的时间范围 - 2

    我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时

  10. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

随机推荐