加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MySql教程 > 正文

MYSQL教程mysql递归查询实现方法

发布时间:2020-12-12 02:47:29 所属栏目:MySql教程 来源:网络整理
导读:《MYSQL教程mysql递归查询实现方法》要点: 本文介绍了MYSQL教程mysql递归查询实现方法,希望对您有用。如果有疑问,可以联系我们。 导读:在Oracle 中有一个 Hierarchical Queries 通过CONNECT BY 可以方便的查了所有当前节点下的所有子节点.在MySQL的目前

《MYSQL教程mysql递归查询实现方法》要点:
本文介绍了MYSQL教程mysql递归查询实现方法,希望对您有用。如果有疑问,可以联系我们。

导读:在Oracle 中有一个 Hierarchical Queries 通过CONNECT BY 可以方便的查了所有当前节点下的所有子节点.在MySQL的目前版本中还没有对...

MYSQL应用在Oracle 中有一个 Hierarchical Queries 通过CONNECT BY 可以方便的查了所有当前节点下的所有子节点.
在MySQL的目前版本中还没有对应的功能.
?
在MySQL中如果是有限的层次,比如事先如果可以确定这个树的最大深度是4,那么所有节点为根的树的深度均不会超过4,则可以直接通过left join 来实现.
?
但有时无法控制树的深度.这时就需要在MySQL中用存储过程来实现或在你的程序中来实现这个递归.

MYSQL应用本文讨论一下几种实现的办法.
?
样例数据:
?

mysql> create table treeNodes
??? -> (
??? ->? id int primary key,
??? ->? nodename varchar(20),
??? ->? pid int
??? -> );
Query OK,0 rows affected (0.09 sec)
mysql> select * from treenodes;
+----+----------+------+
| id | nodename | pid? |
+----+----------+------+
|? 1 | A??????? |??? 0 |
|? 2 | B??????? |??? 1 |
|? 3 | C??????? |??? 1 |
|? 4 | D??????? |??? 2 |
|? 5 | E??????? |??? 2 |
|? 6 | F??????? |??? 3 |
|? 7 | G??????? |??? 6 |
|? 8 | H??????? |??? 0 |
|? 9 | I??????? |??? 8 |
| 10 | J??????? |??? 8 |
| 11 | K??????? |??? 8 |
| 12 | L??????? |??? 9 |
| 13 | M??????? |??? 9 |
| 14 | N??????? |?? 12 |
| 15 | O??????? |?? 12 |
| 16 | P??????? |?? 15 |
| 17 | Q??????? |?? 15 |
+----+----------+------+
17 rows in set (0.00 sec)
?

MYSQL应用树形图:
?

1:A
? +-- 2:B
? |??? +-- 4:D
? |??? +-- 5:E
? +-- 3:C
?????? +-- 6:F
??????????? +-- 7:G
?8:H
? +-- 9:I
? |??? +-- 12:L
? |??? |??? +--14:N
? |??? |??? +--15:O
? |??? |??????? +--16:P
? |??? |??????? +--17:Q
? |??? +-- 13:M
? +-- 10:J
? +-- 11:K?
?

MYSQL应用?
办法一:利用函数来得到所有子节点号.
创建一个function getChildLst,得到一个由所有子节点号组成的字符串.
?

MYSQL应用mysql> delimiter //
mysql>
mysql> CREATE FUNCTION `getChildLst`(rootId INT)
??? -> RETURNS varchar(1000)
??? -> BEGIN
??? ->?? DECLARE sTemp VARCHAR(1000);
??? ->?? DECLARE sTempChd VARCHAR(1000);
??? ->
??? ->?? SET sTemp = '$';
??? ->?? SET sTempChd =cast(rootId as CHAR);
??? ->
??? ->?? WHILE sTempChd is not null DO
??? ->???? SET sTemp = concat(sTemp,',sTempChd);
??? ->???? SELECT group_concat(id) INTO sTempChd FROM treeNodes where FIND_IN_SET(pid,sTempChd)>0;
??? ->?? END WHILE;
??? ->?? RETURN sTemp;
??? -> END
??? -> //
Query OK,0 rows affected (0.00 sec)

MYSQL应用mysql>
mysql> delimiter ;

MYSQL应用使用直接利用find_in_set函数配合这个getChildlst来查找:
?

MYSQL应用mysql> select getChildLst(1);
+-----------------+
| getChildLst(1)? |
+-----------------+
| $,1,2,3,4,5,6,7 |
+-----------------+
1 row in set (0.00 sec)

MYSQL应用mysql> select * from treeNodes
??? -> where FIND_IN_SET(id,getChildLst(1));
+----+----------+------+
| id | nodename | pid? |
+----+----------+------+
|? 1 | A??????? |??? 0 |
|? 2 | B??????? |??? 1 |
|? 3 | C??????? |??? 1 |
|? 4 | D??????? |??? 2 |
|? 5 | E??????? |??? 2 |
|? 6 | F??????? |??? 3 |
|? 7 | G??????? |??? 6 |
+----+----------+------+
7 rows in set (0.01 sec)

MYSQL应用mysql> select * from treeNodes
??? -> where FIND_IN_SET(id,getChildLst(3));
+----+----------+------+
| id | nodename | pid? |
+----+----------+------+
|? 3 | C??????? |??? 1 |
|? 6 | F??????? |??? 3 |
|? 7 | G??????? |??? 6 |
+----+----------+------+
3 rows in set (0.01 sec)
?
?

MYSQL应用优点: 简单,方便,没有递归调用层次深度的限制 (max_sp_recursion_depth,最大255) ;
缺点:长度受限,虽然可以扩大 RETURNS varchar(1000),但总是有最大限制的.
MySQL目前版本( 5.1.33-community)中还不支持function 的递归调用.
?
办法二:利用临时表和过程递归
创建存储过程如下.createChildLst 为递归过程,showChildLst为调用入口过程,准备临时表及初始化.
?

MYSQL应用mysql> delimiter //
mysql>
mysql> # 入口过程
mysql> CREATE PROCEDURE showChildLst (IN rootId INT)
??? -> BEGIN
??? ->? CREATE TEMPORARY TABLE IF NOT EXISTS tmpLst
??? ->?? (sno int primary key auto_increment,id int,depth int);
??? ->? DELETE FROM tmpLst;
??? ->
??? ->? CALL createChildLst(rootId,0);
??? ->
??? ->? select tmpLst.*,treeNodes.* from tmpLst,treeNodes where tmpLst.id=treeNodes.id order by tmpLst.sno;
??? -> END;
??? -> //
Query OK,0 rows affected (0.00 sec)

MYSQL应用mysql>
mysql> # 递归过程
mysql> CREATE PROCEDURE createChildLst (IN rootId INT,IN nDepth INT)
??? -> BEGIN
??? ->? DECLARE done INT DEFAULT 0;
??? ->? DECLARE b INT;
??? ->? DECLARE cur1 CURSOR FOR SELECT id FROM treeNodes where pid=rootId;
??? ->? DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
??? ->
??? ->? insert into tmpLst values (null,rootId,nDepth);
??? ->
??? ->? OPEN cur1;
??? ->
??? ->? FETCH cur1 INTO b;
??? ->? WHILE done=0 DO
??? ->????????? CALL createChildLst(b,nDepth+1);
??? ->????????? FETCH cur1 INTO b;
??? ->? END WHILE;
??? ->
??? ->? CLOSE cur1;
??? -> END;
??? -> //
Query OK,0 rows affected (0.00 sec)
mysql> delimiter ;

MYSQL应用调用时传入结点:
?

MYSQL应用mysql> call showChildLst(1);
+-----+------+-------+----+----------+------+
| sno | id?? | depth | id | nodename | pid? |
+-----+------+-------+----+----------+------+
|?? 4 |??? 1 |???? 0 |? 1 | A??????? |??? 0 |
|?? 5 |??? 2 |???? 1 |? 2 | B??????? |??? 1 |
|?? 6 |??? 4 |???? 2 |? 4 | D??????? |??? 2 |
|?? 7 |??? 5 |???? 2 |? 5 | E??????? |??? 2 |
|?? 8 |??? 3 |???? 1 |? 3 | C??????? |??? 1 |
|?? 9 |??? 6 |???? 2 |? 6 | F??????? |??? 3 |
|? 10 |??? 7 |???? 3 |? 7 | G??????? |??? 6 |
+-----+------+-------+----+----------+------+
7 rows in set (0.13 sec)

MYSQL应用Query OK,0 rows affected,1 warning (0.14 sec)

MYSQL应用mysql>
mysql> call showChildLst(3);
+-----+------+-------+----+----------+------+
| sno | id?? | depth | id | nodename | pid? |
+-----+------+-------+----+----------+------+
|?? 1 |??? 3 |???? 0 |? 3 | C??????? |??? 1 |
|?? 2 |??? 6 |???? 1 |? 6 | F??????? |??? 3 |
|?? 3 |??? 7 |???? 2 |? 7 | G??????? |??? 6 |
+-----+------+-------+----+----------+------+
3 rows in set (0.11 sec)

MYSQL应用Query OK,1 warning (0.11 sec)
?

MYSQL应用depth 为深度,这样可以在程序进行一些显示上的格式化处理.类似于oracle中的 level 伪列.sno 仅供排序控制.
这样还可以通过临时表tmpLst与数据库中其它表进行联接查询.
?
MySQL中可以利用系统参数 max_sp_recursion_depth 来控制递归调用的层数上限.如下例设为12.
?

mysql> set max_sp_recursion_depth=12;
Query OK,0 rows affected (0.00 sec)
?

MYSQL应用?
优点 : 可以更灵活处理,及层数的显示.并且可以依照树的遍历顺序得到结果.
缺点 : 递归有255的限制.
?
方法三:利用中间表和过程
(本方法由yongyupost2000提供样子改编)
创建存储过程如下.
由于MySQL中不允许在同一语句中对临时表多次引用,只以使用普通表tmpLst来实现了.
当然程序中负责在用完后清除这个表.
?

delimiter //
drop PROCEDURE IF EXISTS? showTreeNodes_yongyupost2000//
CREATE PROCEDURE showTreeNodes_yongyupost2000 (IN rootid INT)
BEGIN
?DECLARE Level int ;
?drop TABLE IF EXISTS tmpLst;
?CREATE TABLE tmpLst (
? id int,
? nLevel int,
? sCort varchar(8000)
?);
?
?Set Level=0 ;
?INSERT into tmpLst SELECT id,Level,ID FROM treeNodes WHERE PID=rootid;
?WHILE ROW_COUNT()>0 DO
? SET Level=Level+1 ;
? INSERT into tmpLst
?? SELECT A.ID,concat(B.sCort,A.ID) FROM treeNodes A,tmpLst B
??? WHERE? A.PID=B.ID AND B.nLevel=Level-1? ;
?END WHILE;
?
END;
//
delimiter ;
CALL showTreeNodes_yongyupost2000(0);
?

MYSQL应用执行完后会产生一个tmpLst表,nLevel 为节点深度,sCort 为排序字段.
使用办法:
?

SELECT concat(SPACE(B.nLevel*2),'+--',A.nodename)
FROM treeNodes A,tmpLst B
WHERE A.ID=B.ID
ORDER BY B.sCort;
?
+--------------------------------------------+
| concat(SPACE(B.nLevel*2),A.nodename) |
+--------------------------------------------+
| +--A?????????????????????????????????????? |
|?? +--B???????????????????????????????????? |
|???? +--D?????????????????????????????????? |
|???? +--E?????????????????????????????????? |
|?? +--C???????????????????????????????????? |
|???? +--F?????????????????????????????????? |
|?????? +--G???????????????????????????????? |
| +--H?????????????????????????????????????? |
|?? +--J???????????????????????????????????? |
|?? +--K???????????????????????????????????? |
|?? +--I???????????????????????????????????? |
|???? +--L?????????????????????????????????? |
|?????? +--N???????????????????????????????? |
|?????? +--O???????????????????????????????? |
|???????? +--P?????????????????????????????? |
|???????? +--Q?????????????????????????????? |
|???? +--M?????????????????????????????????? |
+--------------------------------------------+
17 rows in set (0.00 sec)

MYSQL应用以上介绍了mysql递归查询的实现办法与实例代码,希望对大家有所帮助.

《MYSQL教程mysql递归查询实现方法》是否对您有启发,欢迎查看更多与《MYSQL教程mysql递归查询实现方法》相关教程,学精学透。编程之家PHP学院为您提供精彩教程。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读