精华内容
下载资源
问答
  • mysql递归查询子节点

    千次阅读 2019-06-15 13:52:24
    背景 项目中遇到一个需求,要求查处菜单节点的所有节点,在网上查了一下,大多数的方法用到了存储过程,由于线上环境不能随便添加存储过程, ...因此在这里采用类似递归的方法对菜单的所有子节点进行查询。 ...

    背景                                                                                                      

    项目中遇到一个需求,要求查处菜单节点的所有节点,在网上查了一下,大多数的方法用到了存储过程,由于线上环境不能随便添加存储过程,

    因此在这里采用类似递归的方法对菜单的所有子节点进行查询。

    准备                                                                                                        

    创建menu表:

     

    CREATE TABLE `menu` (
      `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '菜单id',
      `parent_id` int(11) DEFAULT NULL COMMENT '父节点id',
      `menu_name` varchar(128) DEFAULT NULL COMMENT '菜单名称',
      `menu_url` varchar(128) DEFAULT '' COMMENT '菜单路径',
      `status` tinyint(3) DEFAULT '1' COMMENT '菜单状态 1-有效;0-无效',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=12212 DEFAULT CHARSET=utf8;

    插入数据:

    INSERT INTO `menu` VALUES ('0', null, '菜单0', ' ', '1');
    INSERT INTO `menu` VALUES ('1', '0', '菜单1', '', '1');
    INSERT INTO `menu` VALUES ('11', '1', '菜单11', '', '1');
    INSERT INTO `menu` VALUES ('12', '1', '菜单12', '', '1');
    INSERT INTO `menu` VALUES ('13', '1', '菜单13', '', '1');
    INSERT INTO `menu` VALUES ('111', '11', '菜单111', '', '1');
    INSERT INTO `menu` VALUES ('121', '12', '菜单121', '', '1');
    INSERT INTO `menu` VALUES ('122', '12', '菜单122', '', '1');
    INSERT INTO `menu` VALUES ('1221', '122', '菜单1221', '', '1');
    INSERT INTO `menu` VALUES ('1222', '122', '菜单1222', '', '1');
    INSERT INTO `menu` VALUES ('12211', '1222', '菜单12211', '', '1');

     得到的目录结构如下图所示:

    查询                                                                                                            

     先贴出sql语句:

    1

    2

    3

    4

    5

    6

    7

    8

    select id from (

                  select t1.id,

                  if(find_in_set(parent_id, @pids) > 0@pids := concat(@pids',', id), 0) as ischild

                  from (

                       select id,parent_id from re_menu t where t.status = 1 order by parent_id, id

                      ) t1,

                      (select @pids := 要查询的菜单节点 id) t2

                 ) t3 where ischild != 0

     比如,要查询菜单节点12的所有子节点,则查处的结果为:

     分析                                                                                                             

    首先分析from后面的语句,根据parent_id和id 排序,并将要查询的菜单节点当做变量,from后面的结果为

    接下来看if(express1,express2,express3)条件语句,if语句类似三目运算符,当exprss1成立时,执行express2,否则执行express3;

    FIND_IN_SET(str,strlist),str 要查询的字符串,strlist 字段名 参数以”,”分隔 如 (1,2,6,8),查询字段(strlist)中包含(str)的结果,返回结果为null或记录

    如果parent_id 在@pid中,则将@pid 里面再加上parent_id,按行依次执行,执行过程如下表所示:

    这时,显示的id就是菜单id为12的所有子节点id

     

    ==============================更新于2020-03-11============================

    有细心的网友发现parent_id顺序错乱时以上方法会存在问题,今天抽时间看了下,问题确实存在。

    如以下测试数据会出现结果不准确
    INSERT INTO `menu` VALUES ('0', null, '菜单0', ' ', '1');
    INSERT INTO `menu` VALUES ('1', '0', '菜单1', '', '1');
    INSERT INTO `menu` VALUES ('2', '1', '菜单2', '', '1');
    INSERT INTO `menu` VALUES ('3', '2', '菜单3', '', '1');
    INSERT INTO `menu` VALUES ('4', '3', '菜单4', '', '1');
    INSERT INTO `menu` VALUES ('5', '4', '菜单5', '', '1');
    INSERT INTO `menu` VALUES ('6', '5', '菜单6', '', '1');

    解决方法为:使用function

    DELIMITER //
    
    CREATE  FUNCTION `getChildLst`(rootId varchar(50)) RETURNS varchar(1000) CHARSET utf8
    
    BEGIN
    
    DECLARE sTemp VARCHAR(1000);
    
    DECLARE sTempChd VARCHAR(1000);
    
    SET sTemp = '';
    
    SET sTempChd =rootId;
    
    WHILE sTempChd is not null DO
    
    if sTempChd!=rootId then
    	SET sTemp = concat(sTemp,',',sTempChd);
    end if;
    
    SELECT group_concat(id) INTO sTempChd FROM menu where parent_id<>id and FIND_IN_SET(parent_id,sTempChd)>0;
    
    END WHILE;
    
    RETURN sTemp;
    
    END//

    然后使用select getChildLst('2'); 可以得到正确结果。

     

    展开全文
  • 本程序写了两个sql存储过程,子节点查询算是照搬了,父节点查询是逆思维弄的
  • mysql 递归查询子节点

    2019-11-11 16:31:47
    表结构及数据与oracle递归查询子节点中的一致 数据结构稍有不同 drop table if EXISTS city; create table city( id int primary key, name varchar(50) not null, parent_id int ); sql 1.找出所有的节点 ...

    表结构及数据与oracle递归查询子节点中的一致

    数据结构稍有不同

    drop table if EXISTS city;
    create table city(
    id int primary key,
    name varchar(50) not null,
    parent_id int
    );

    sql

    1.找出所有的节点

    select id,name,parent_id from city t order by parent_id, id 

    2.如果节点的 父id 在 选择的节点id中 将该节点添加到选择的节点集合中(递归)

    select t1.id,t1.name,parent_id,
                  if(find_in_set(parent_id, @pids) > 0, @pids := concat(@pids, ',', id), 0) as ischild
                  from ( select id,name,parent_id from city t order by parent_id, id ) t1,
                      (select @pids := 2) t2

    3.最后将所有子节点返回

    select id,name,ischild from (
                  select t1.id,t1.name,
                  if(find_in_set(parent_id, @pids) > 0, @pids:= concat(@pids, ',', id), 0) as ischild
                  from ( 
                        select id,name,parent_id from city t order by parent_id, id 
                      ) t1,
                      (select @pids:= 选择的节点id) t2
                 ) t3 
    where ischild != 0;

    关键方法

    find_in_set(str,strList) :查询字段(strlist)中包含(str)的结果

        参数:str 要查询的字符串,strlist 字段名 参数以”,”分隔 如 (1,2,6,8)

        结果:不包含——0, 包含——返回第一个存在的位置:select FIND_IN_SET('2', '1,2,6,8'); 结果 2

    if(express1,express2,express3):当exprss1成立时,执行express2,否则执行express3;

    自定义函数实现

    获取所有下级节点id

    drop function if EXISTS getChildren;
    CREATE FUNCTION getChildren (city_id INT) RETURNS VARCHAR (4000)
    BEGIN
    DECLARE result VARCHAR (4000);
    DECLARE child VARCHAR (4000);
    SET result = '';
    SET child = CAST(city_id AS CHAR);
    WHILE child IS NOT NULL DO
    SET result = CONCAT(result, ',', child);
    SELECT
    	GROUP_CONCAT(id) INTO child
    FROM
    	city
    WHERE
    	FIND_IN_SET(parent_id, child) > 0;
    END
    WHILE;
    RETURN result;
    END

    调用

    select * from city where FIND_IN_SET(id,getChildren(2));

    方法/关键字说明

    表达式 into 变量名 将 表达式的值插入到变量中(赋值)

    group_concat([distinct]要连接的字段 [order by 排序字段 asc/desc] [separator '分隔符']) : 将group by 产生的同一个分组中的值连接起来,返回一个字符串结果

        说明:通过使用 distinct 可以去重;如果希望对结果进行排序,可以使用 order by; separator 是一个字符串,缺省为一个逗号,用于分隔连接的字段

        注意:若没有明确有group by 语句时,将所有满足条件的结果作为一个分组

    展开全文
  • Mysql 递归查询子节点

    2020-09-09 10:14:52
    Mysql递归查询 #查询父编码及以下所有子集 SELECT id FROM ( SELECT t1.id,t1.parent_id,IF (find_in_set(t1.id,@pids)> 0,@pids,IF (find_in_set(t1.parent_id,@pids)> 0,@pids :=CONCAT_WS(',',@pids,id),'0...

    Mysql递归查询

    #查询父编码及以下所有子节点
    SELECT id FROM (
    SELECT t1.id,t1.parent_id,IF (find_in_set(t1.id,@pids)> 0,@pids,IF (find_in_set(t1.parent_id,@pids)> 0,@pids :=CONCAT_WS(',',@pids,id),'0')) AS ischild,@pids FROM (
    SELECT t.id,t.parent_id FROM hr_organization t WHERE t.STATUS=1 ORDER BY parent_id,id) t1,(
    SELECT @pids :='YZC0035') t2) t3 WHERE ischild !='0';
    #查询子节点
    SELECT id FROM (
    SELECT t1.id,t1.parent_id, IF (find_in_set(t1.parent_id,@pids)> 0,@pids :=CONCAT_WS(',',@pids,id),'0') AS ischild,@pids FROM (
    SELECT t.id,t.parent_id FROM hr_organization t WHERE t.STATUS=1 ORDER BY parent_id,id) t1,(
    SELECT @pids :='YZC0035') t2) t3 WHERE ischild !='0';
    
    1. @pids :=‘YZC0035’ 定义变量,赋值要查询的父编码
    2. @pids 取值
    3. find_in_set(‘查询的字段’,‘以逗号分隔字符串’) select find_in_set(‘2’,‘1,2’);返回2 不存在返回0
    4. if(express1,express2,express3)条件语句,if语句类似三目运算符,当exprss1成立时,执行express2,否则执行express3
    5. CONCAT_WS 合并字段定义以分隔符
    展开全文
  • mysql没有给出递归方法,需要自定义实现函数,但是在数据库部署的时候,函数往往会被...在这种自定义函数不受欢迎的情况下,可不可以采用别的方法实现查询子节点功能呢,比如放到java中实现。 具体实现思路: ...

    mysql没有给出递归方法,需要自定义实现函数,但是在数据库部署的时候,函数往往会被遗漏(比如使用Navicat导出数据库时,自定义函数可能不会被导出),而且自定义函数相比之下不便于维护。在这种自定义函数不受欢迎的情况下,可不可以采用别的方法实现查询子节点功能呢,比如放到java中实现。

    具体实现思路:比如查找一个节点的子节点,

    首先查询出全部数据,再通过循环+递归得到所有的子节点,这种方法在数据量不大的情况下时间花费比较高,不太合适。

    可以考虑使用前端实现,如果前端是使用树插件来展示数据,可以通过树结构递归得到所有的子节点,再通过后端获取对应的数据。同样的数据条件下,比后端循环+递归的方式要快。(结论不具有普遍性,没有理论支持,只是现场环境下的测试结论)

    后台递归实现:

        /**
         * 递归实现获得所有子节点
         * @param id 待查询节点
         * @param nodeList 节点集合
         * @return
         */
        List<String> findNodeChildren(String id,List<Map> nodeList){
            List<String> list = new ArrayList<>();
    
            for(Map node : nodeList){
                String nodeId = node.get("id") == null ? "":node.get("id").toString();
                String parent = node.get("parent") == null ? "" : node.get("parent").toString();
                //如果该节点为子节点,就收集子节点id
                if(parent.equals(id)){
                    list.add(nodeId);
                    list.addAll(findNodeChildren(nodeId,nodeList));
                }
            }
            return list;
        }

    前台插件递归实现,以bootstrap-treeview控件为例:

    	//获得选中节点的所有子节点
         function getChildrenNode(nodeData){
             var array = [];
             var children = nodeData.nodes;
             if(children){
                 children.forEach( function(item){
                     array.push(item.id);
                     array = array.concat(getChildrenNode(item));
                 } );
             }
             return array;
         }

    展开全文
  • NAVICAT中截图 表结构如下图 ...查询节点 代码如下 BEGIN DECLARE i varchar(100) default ''; DECLARE j varchar(1000) default rootId; WHILE rootId is not null do SET i =...
  • END 查集合 --drop FUNCTION `getChildList` CREATE FUNCTION `getChildList`(rootId varchar(100)) RETURNS varchar(2000) BEGIN DECLARE str varchar(2000); DECLARE cid varchar(100); SET str = '$'; SET cid...
  • mysql递归查询子节点,java后台获取存储过程数据
  • 在开发中,我们经常遇到通过父级节点查询所有子节点的需求,我们知道在mysql中我们可以自定义函数的方式来实现这个功能,但是自定义函数根据父节点递归查询所有子节点的方法需要额外维护函数,故而增加了维护成本,...
  • mysql 递归查找所有子节点

    千次阅读 2021-01-15 09:43:39
    查询树的子节点不包括当前节点: select dept_id from ( 2 select t1.dept_id,t1.parent_id, 3 if(find_in_set(parent_id, @pids) > 0, @pids := concat(@pids, ',', dept_id), 0) as ischild 4 from ( 5 select ...
  • 一般大家都喜欢在mysql中写递归函数查询子节点如下:   CREATE DEFINER = `mysql_xxx`@`%` FUNCTION `NewProc`(pid VARCHAR(40), holdPid INT) RETURNS varchar(20000) BEGIN #根据指定ID获取下级模块所有节点...
  • 因此在这里采用类似递归的方法对菜单的所有子节点进行查询。 准备 创建menu表: CREATE TABLE `menu` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '菜单id', `parent_id` int(11) DEFAULT NULL COMMENT '父...
  • 根据父节点查找所有的子节点 创建函数getChildrenList SQL语句如下: delimiter // CREATE FUNCTION `getChildrenList`(rootId INT) RETURNS varchar(1000) BEGIN DECLARE sTemp VARCHAR(1000); DECLARE ...
  • mysql 递归查询父节点及子节点

    千次阅读 2017-07-18 11:00:19
    查询节点 Drop FUNCTION if EXISTS `getParentList`; CREATE FUNCTION `getParentList`(rootId varchar(100)) RETURNS varchar(1000) BEGIN DECLARE fid varchar(100) default ''; DECLARE str varch
  • //SQL SqlServer:CTE函数处理递归(WITH语法) cte可以其他名字 注意匹配(所有cte全部替换) with cte as ( select a.typeid,a.superid,a.typename from ctype a where typeid=1 union all select k.typeid...
  • 对于数据库中的树形结构数据,我们经常会有一种需求,给定一个父节点,查询这个父节点下所有的子节点,或者给定一个子节点查询这个子节点上的所有父节点。 接下来,我将介绍如何在MySql中使用函数来实现递归。 1....
  • 当我们查询所有的当前部门下以及当前部门下面的所有子部门,需要就需要我们获取所有当前节点和子节点的id,这里使用mysql递归查询来实现。查找给定分类编码查找分类及其所有子类,包含子类的子类。 二、实现sql ...
  • mysql -- 递归查询所有子节点

    万次阅读 2017-09-26 17:09:16
    背景有个需求,查询一个文件中的所有目录的文件及文件夹。实现1. 数据库设计首先, 建立一张 t_files 表, 模拟文件树结构。 create table `t_files` ( id int auto_increment, file_name varchar(100) default ...
  • 背景  项目中遇到一个需求,要求查处菜单节点的所有节点,在网上查了一下,大多数的方法用到了存储过程,由于线上环境不能随便添加存储过程, ...因此在这里采用类似递归的方法对菜单的所有子节点进行查询。 ...
  • MySQL递归查询父子节点

    千次阅读 2019-03-01 13:37:28
    1.表结构 CREATE TABLE folder( id BIGINT(20) NOT NULL, parent_id BIGINT(20) DEFAULT ...2.根据传入id查询所有父节点及其的id 创建函数: CREATE DEFINER=`root`@`%` FUNCTION `getParList`(rootId BIGI...
  • 根据id查询节点,具体需要修改的地方笔者已在注释中给大家作了注解 DELIMITER $$ USE `yjlc_platform`$$ -- getCompanyParent 为函数名 DROP FUNCTION IF EXISTS `getCompanyParent`$$ -- ...
  • 对于数据库中的树形结构数据,如部门表,有时候,我们需要知道某部门的所有下属部分或者某部分的所有上级部门,这时候就需要用到mysql递归查询 最近在做项目迁移,Oracle版本的迁到Mysql版本,遇到有些oracle的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 13,127
精华内容 5,250
关键字:

mysql递归查询子节点

mysql 订阅