《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学院为您提供精彩教程。 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|