目前的mysql版本中并不支持直接的递归查询,但是通过递归到迭代转化的思路,可以在一句SQL内实现树的递归查询

下面给一个小示例,后续在贴上调用的代码(代码会贴在最后请注意)

MySQL递归查询所有子节点,树形结构查询

--表结构

CREATE TABLE `address` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`code_value` varchar(32) DEFAULT NULL COMMENT '区域编码',
`name` varchar(128) DEFAULT NULL COMMENT '区域名称',
`remark` varchar(128) DEFAULT NULL COMMENT '说明',
`pid` varchar(32) DEFAULT NULL COMMENT 'pid是code_value',
PRIMARY KEY (`id`),
KEY `ix_name` (`name`,`code_value`,`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=1033 DEFAULT CHARSET=utf8 COMMENT='行政区域表';

--mysql 实现树结构查询
--方法一

CREATE PROCEDURE sp_showChildLst(IN rootId varchar(20))
BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS tmpLst
(sno int primary key auto_increment,code_value VARCHAR(20),depth int);
DELETE FROM tmpLst;

CALL sp_createChildLst(rootId,0);

select tmpLst.*,address.* from tmpLst,address where tmpLst.code_value=address.code_value order by tmpLst.sno;
END

CREATE PROCEDURE sp_createChildLst(IN rootId varchar(20),IN nDepth INT)
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE b VARCHAR(20);
DECLARE cur1 CURSOR FOR SELECT code_value FROM address where pid=rootId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

insert into tmpLst values (null,rootId,nDepth);

SET @@max_sp_recursion_depth = 10;
OPEN cur1;

FETCH cur1 INTO b;
WHILE done=0 DO
CALL sp_createChildLst(b,nDepth+1);
FETCH cur1 INTO b;
END WHILE;

CLOSE cur1;
END

--方法二(此方法有线程安全问题)

CREATE PROCEDURE sp_getAddressChild_list(in idd varchar(36))
begin
declare lev int;
set lev=1;
drop table if exists tmp1;
CREATE TABLE tmp1(code_value VARCHAR(36),`name` varchar(50),pid varchar(36) ,levv INT);
INSERT tmp1 SELECT code_value,`name`,pid,1 FROM address WHERE pid=idd;
while row_count()>0
do
set lev=lev+1;
INSERT tmp1 SELECT t.code_value,t.`name`,t.pid,lev from address t join tmp1 a on t.pid=a.code_value AND levv=lev-1;
end while ;
INSERT tmp1 SELECT code_value,`name`,pid,0 FROM address WHERE code_value=idd;
SELECT * FROM tmp1;
end

--方法三

CREATE FUNCTION fn_getAddress_ChildList_test(rootId INT) RETURNS varchar(1000) CHARSET utf8 #rootId为你要查询的节点
BEGIN

#声明两个临时变量
DECLARE temp VARCHAR(1000);
DECLARE tempChd VARCHAR(1000);
SET temp = '$';
SET tempChd=CAST(rootId AS CHAR);#把rootId强制转换为字符

WHILE tempChd is not null DO
SET temp = CONCAT(temp,',',tempChd);#循环把所有节点连接成字符串。
SELECT GROUP_CONCAT(code_value) INTO tempChd FROM address where FIND_IN_SET(pid,tempChd)>0;
END WHILE;
RETURN temp;

END

--方法四

CREATE PROCEDURE sp_findAddressChild(iid varchar(50),layer bigint(20))
BEGIN 
/*创建接受查询的临时表 */ 
create temporary table if not exists tmp_table(id varchar(50),code_value varchar(50),name varchar(50),pid VARCHAR(50)) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
/*最高允许递归数*/ 
SET @@max_sp_recursion_depth = 10 ; 
call sp_iterativeAddress(iid,layer);/*核心数据收集*/ 
select * from tmp_table ;/* 展现 */ 
drop temporary table if exists tmp_table ;/*删除临时表*/ 
END

CREATE PROCEDURE sp_iterativeAddress(iid varchar(50),layer bigint(20))
BEGIN 
DECLARE t_id INT;
declare t_codeValue varchar(50) default iid ; 
declare t_name varchar(50) character set utf8; 
declare t_pid varchar(50) character set utf8;

/* 游标定义 */ 
declare cur1 CURSOR FOR select id,code_value,`name`,pid from address where pid=iid ; 
declare CONTINUE HANDLER FOR SQLSTATE '02000' SET t_codeValue = null;

/* 允许递归深度 */ 
if layer>0 then 
OPEN cur1 ; 
FETCH cur1 INTO t_id,t_codeValue,t_name,t_pid ; 
WHILE ( t_codeValue is not null ) 
DO 
/* 核心数据收集 */ 
insert into tmp_table values(t_id,t_codeValue,t_name,t_pid); 
call sp_iterativeAddress(t_codeValue,layer-1); 
FETCH cur1 INTO t_id,t_codeValue,t_name,t_pid ; 
END WHILE; 
end if; 
END

--方法五 SQL实现

SELECT `name`,code_value AS code_value,pid AS 父ID ,levels AS 父到子之间级数, paths AS 父到子路径 FROM (
SELECT `name`,code_value,pid,
@le:= IF (pid = 0 ,0, 
IF( LOCATE( CONCAT('|',pid,':'),@pathlevel) > 0 , 
SUBSTRING_INDEX( SUBSTRING_INDEX(@pathlevel,CONCAT('|',pid,':'),-1),'|',1) +1
,@le+1) ) levels
, @pathlevel:= CONCAT(@pathlevel,'|',code_value,':', @le ,'|') pathlevel
, @pathnodes:= IF( pid =0,',0', 
CONCAT_WS(',',
IF( LOCATE( CONCAT('|',pid,':'),@pathall) > 0 , 
SUBSTRING_INDEX( SUBSTRING_INDEX(@pathall,CONCAT('|',pid,':'),-1),'|',1)
,@pathnodes ) ,pid ) )paths
,@pathall:=CONCAT(@pathall,'|',code_value,':', @pathnodes ,'|') pathall 
FROM address, 
(SELECT @le:=0,@pathlevel:='', @pathall:='',@pathnodes:='') vv
ORDER BY pid,code_value
) src
ORDER BY pid

--方法6  存储过程(SQL实现)

create procedure query_all_add_children(in inPid varchar(50))
begin
select id,code_value,name,remark,pid,p2id,p3id,p4id,p5id 
from(
select a1.id,a1.code_value,a1.name,a1.remark,
a1.pid,a2.pid p2id,a3.pid p3id,a4.pid p4id,a5.pid p5id 
from 
address a1 left join address a2
on(a1.pid=a2.code_value)
left join address a3
on(a2.pid=a3.code_value)
left join address a4
on(a3.pid=a4.code_value)
left join address a5
on(a4.pid=a5.code_value)
) al
where 
(pid=inPid
or p2id=inPid
or p3id=inPid
or p4id=inPid
or p5id=inPid
);
end

我是用的方法6:取出所有节点利用MySql函数截取所需要的字符串,然后在SQL中字段IN(调用此方法)来进行查询,这样效率比较高,方法1效率也较高,其他方法都有效率问题

以下是代码资料,查子集或父级id字符串然后in的方式拼入sql

下面以部门为例,表结构如下(主要使用了department_id 和 parent_id字段):

CREATE TABLE `t_system_department` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `department_id` int(11) NOT NULL COMMENT '部门ID',
  `surname` varchar(100) NOT NULL COMMENT '部门名称',
  `state` int(11) NOT NULL COMMENT '状态 0-有效 1-失效 ',
  `dept_level` varchar(10) NOT NULL COMMENT '层级',
  `paths` varchar(2000) NOT NULL COMMENT '路径',
  `leader_code` varchar(10) NOT NULL COMMENT '负责人编号',
  `parent_id` int(11) DEFAULT NULL COMMENT '上级部门ID',
  `area_section` varchar(50) DEFAULT NULL COMMENT '区域段',
  `dept_section` varchar(50) DEFAULT NULL COMMENT '部门段',
  `line_section` varchar(50) DEFAULT NULL COMMENT '事业部段',
  `creater` int(11) NOT NULL COMMENT '创建人编号',
  `create_date` datetime NOT NULL COMMENT '创建日期',
  `updater` int(11) NOT NULL COMMENT '修改人编号',
  `update_date` datetime NOT NULL COMMENT '修改日期',
  PRIMARY KEY (`id`),
  UNIQUE KEY `IDXU_t_systeent_departme_idBD2A` (`department_id`),
  KEY `IDX_t_systeent_parent_id051A` (`parent_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4555 DEFAULT CHARSET=utf8 COMMENT='部门信息表 ;

存储过程

查子集的存储过程:

create procedure sp_createChildLst(IN rootId varchar(20),IN nDepth INT)

BEGIN

DECLARE done INT DEFAULT 0;
DECLARE b VARCHAR(20);
DECLARE cur1 CURSOR FOR SELECT department_id FROM t_system_department where parent_id=rootId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
insert into tmpLst values (null,rootId,nDepth);
SET @@max_sp_recursion_depth = 10;
OPEN cur1;
FETCH cur1 INTO b;
WHILE done=0 DO
CALL sp_createChildLst(b,nDepth+1);
FETCH cur1 INTO b;
END WHILE;
CLOSE cur1;

END

create procedure sp_showChildLst(IN rootId varchar(20))

BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS tmpLst
(sno int primary key auto_increment,department_id VARCHAR(20),depth int);
DELETE FROM tmpLst;
CALL sp_createChildLst(rootId,0);
select group_concat(dept.department_id separator ',') from tmpLst,t_system_department dept where tmpLst.department_id=dept.department_id order by tmpLst.sno;

END

xml调用存储过程

<!-- 查询所有子部门ID字符串,用逗号分隔 -->
<select id="selectChildIds" resultType="java.lang.String" parameterType="java.lang.Integer" statementType="CALLABLE">
        <![CDATA[ 
        {call sp_showChildLst(#{departmentId,mode=IN,jdbcType=INTEGER})};
        ]]>

</select>

dao层接收id字符串

/**
* 根据部门ID获取子部门id字符串,并用逗号分隔
* @param departmentId
* @return
*/

String selectChildIds(@Param(value="departmentId") Integer departmentId);

程序调用如下

xml中拼入id集合


以上部分代码是查询所有子部门的,下面提出查询所有父级的代码


查父集的存储过程:

create procedure sp_createParentLst(IN childId varchar(20),IN nDepth INT)

BEGIN
DECLARE done INT DEFAULT 0;
DECLARE b VARCHAR(20);
DECLARE cur1 CURSOR FOR SELECT parent_id FROM t_system_department where department_id=childId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
insert into tmpPLst values (null,childId,nDepth);
SET @@max_sp_recursion_depth = 10;
OPEN cur1;
FETCH cur1 INTO b;
WHILE done=0 DO
CALL sp_createParentLst(b,nDepth+1);
FETCH cur1 INTO b;
END WHILE;
CLOSE cur1;

END

create procedure sp_showParentLst(IN childId varchar(20))

BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS tmpPLst
(sno int primary key auto_increment,department_id VARCHAR(20),depth int);
DELETE FROM tmpPLst;
CALL sp_createParentLst(childId,0);
select group_concat(dept.department_id separator ',') from tmpPLst,t_system_department dept where tmpPLst.department_id=dept.department_id order by tmpPLst.sno;
END

xml调用存储过程

<!-- 查询所有父级部门ID字符串,用逗号分隔 -->
<select id="selectParentIds" resultType="java.lang.String" parameterType="java.lang.Integer" statementType="CALLABLE">
        <![CDATA[ 
        {call sp_showParentLst(#{departmentId,mode=IN,jdbcType=INTEGER})};
        ]]>
</select>

dao层接收id字符串

/**
* 根据部门ID获取父级部门id字符串,并用逗号分隔
* @param departmentId
* @return
*/
    String selectParentIds(@Param(value="departmentId") Integer departmentId);

下面给出网上常用的一种方式(使用函数的方式),开始我也用了下,数据量不太可以用下,但是数据太多的时候存在严重的效率问题(供参考)

子集:

CREATE PROCEDURE getChildDept(deptId INT varchar(4000))

BEGIN
DECLARE sTemp VARCHAR(4000);
DECLARE sTempChd VARCHAR(4000);

SET sTemp = '$';
SET sTempChd = cast(deptId as char);

WHILE sTempChd is not NULL DO
SET sTemp = CONCAT(sTemp,',',sTempChd);
SELECT group_concat(department_id) INTO sTempChd FROM t_system_department where FIND_IN_SET(parent_id,sTempChd)>0;
END WHILE;
return sTemp;

END

父级:

CREATE PROCEDURE getParentDept(rootId INT varchar(4000))

BEGIN
DECLARE sTemp VARCHAR(1000);
DECLARE sTempPar VARCHAR(1000); 
SET sTemp = ''; 
SET sTempPar =rootId; 
#循环递归
WHILE sTempPar is not null DO 
#判断是否是第一个,不加的话第一个会为空
IF sTemp != '' THEN
SET sTemp = concat(sTemp,',',sTempPar);
ELSE
SET sTemp = sTempPar;
END IF;
SET sTemp = concat(sTemp,',',sTempPar); 
SELECT group_concat(parent_id) INTO sTempPar FROM t_system_department where parent_id<>department_id and FIND_IN_SET(department_id,sTempPar)>0; 
END WHILE; 
RETURN sTemp; 
END

sql查询方式(子父集调用方式一样,函数不同这个就贴出一条供参考):

select  d.department_id 
from  t_system_department d

where FIND_IN_SET(d.department_id,getParentDept(#{entity.departmentId})) 

             and e.department_id=d.department_id)

程序调用调用和子集操作是一样的,在这里就不啰嗦了,调用都比较简单就没有全部贴出了,在下不才欢迎各位提出宝贵建议

MySQL部门或菜单父子节点递归实现树查询相关推荐

  1. java 递归获取树的父节点_Java 树父节点递归获取树子节点

    package nodes4j; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * ...

  2. js 递归查询所有的叶子结点_json树递归js查询json父子节点

    json-query var json = [{ "MenuCode": "S0-3100-00", "MenuAction": " ...

  3. react重新渲染菜单_React实现递归组件

    前言 今天来实现一个 React 的递归组件.具体的效果图如下: 图片说明 假设后端返回的数据如下: [{ id: 1, parent_id: 0, name: '广东省', children: [{ ...

  4. Ztree勾选节点后取消勾选其父子节点

    前言: Ztree官方给的API可以设置勾选一个节点的同时勾选子节点或者父节点,也可以设置不影响父子节点,即将chkboxType设置为{"Y":"",&quo ...

  5. element UI中的el-tree的父子节点添加动态图标

    el-tree的父子节点添加动态icon 最近做的项目,需要给el-tree菜单,展开后的父子节点带有它们自己的icon,因为这个菜单数据是从后台获取的,每一个节点都有属于它们的icon 解决方案如下 ...

  6. 前端VUE【实战】—— antd tree树形控件进行增删改查父子节点

    个人博客:前端江太公 前言 antd 对树形控件目录进行增删改查 最近在用Ant Design写一个后台,遇到的需求就是实现一个可动态增减和编辑子节点的Tree. 实现的效果如下: 可以增加父子节点 ...

  7. mysql之递归树查询

    mysql之递归树查询   写在前面   最近一段时间做的产品使用到了mysql数据库,虽然之前也使用过,但都是在业余时间使用,真正在项目中使用还是发现mysql的一些不同之处,比如函数.存储过程等, ...

  8. SQL 递归查询所有父子节点

    原 SQL 递归查询所有父子节点 2016年05月16日 22:57:16 名贤集 阅读数 21628 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net ...

  9. mysql基础入门 day2 动力节点[老杜]课堂笔记

    day_2 本文原作者为动力节点教学总监杜老师老杜在其课老杜带你学_mysql 入门基础(mysql 基础视频+数据库实战)所写讲课笔记 该文档和其涉及资料见文档末链接 本人将其讲课笔记 txt 下载 ...

最新文章

  1. 【转】ActiveMQ消息传送机制以及ACK机制详解
  2. go的http包详解
  3. Codeforces 1286C/1287E Madhouse (交互题)
  4. 《信号检测与处理》的学习
  5. Java转gcode,学用树莓派(8)-实战案例:基于树莓派JAVA的微型激光雕刻机
  6. CSS清除浮动的五种常用方法
  7. UItextField 的属性
  8. Kafka : kafka无法消费的情况
  9. protobuf vc2008编译
  10. 【Git/Github学习笔记】Git常用命令(推送到远程)
  11. 打造薪酬体系,有效激励员工 穆穆-movno1
  12. PHP根据经纬度计算距离
  13. 使用PS蒙版功能去水印以及Word中的图片合并功能合并公司Logo图片
  14. 笔记本如何实现USB外接键盘开机?
  15. 我们是如何设计出,让玩家们有“上瘾症”的抽卡系统的
  16. Itext使用 Java导出PDF
  17. Qt 微内核架构实践
  18. 联通光猫f677v2改桥接的辛酸历程
  19. ElasticSearch pinyin分词支持多音字
  20. ajax 获取数据

热门文章

  1. java调用三汇语音卡,杭州三汇语音卡电话拨号程序源代码(c#)
  2. 个人支付接口开通(教程)
  3. 笔记本电脑登录校园网,但上不了网
  4. 阿里云直播GRTN和RTC技术谈
  5. [msdn] WritePrivateProfileString 写入配置文件
  6. 小程序关联微信视频号
  7. Adobe推验证系统 检测盗版软件
  8. 【JavaScript 教程】浏览器—浏览器环境概述
  9. 图解说明——究竟什么是Windows句柄
  10. 关乎mysql数据库的连接查询和子查询的效率问题