집 >데이터 베이스 >MySQL 튜토리얼 >MySQL은 트리 순회(다단계 메뉴 표시줄 및 다단계 상위 및 하위 부서에 대한 질문)를 구현합니다.
머리말:
다단계 메뉴바에서 상위, 하위 부서 트리 순회 또는 권한에 대해 시스템, oracle 이를 달성하기 위해 MySQL에는 연결이 있습니다. MySQL에는 이러한 편리한 방법이 없으므로 데이터 테이블을 탐색하는 MySQL은 저장 프로시저를 통해 자주 발생하는 문제입니다.
1. 테스트 테이블 및 데이터 생성:
DROP TABLE IF EXISTS csdn.channel; CREATE TABLE csdn.channel ( id INT(11) NOT NULL AUTO_INCREMENT, cname VARCHAR(200) DEFAULT NULL, parent_id INT(11) DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=INNODB DEFAULT CHARSET=utf8; INSERT INTO channel(id,cname,parent_id) VALUES (13,'首页',-1), (14,'TV580',-1), (15,'生活580',-1), (16,'左上幻灯片',13), (17,'帮忙',14), (18,'栏目简介',17); DROP TABLE IF EXISTS channel;
2, 임시 테이블 및 재귀 사용 프로세스는 트리 탐색을 구현합니다(mysql의 UDF는 재귀적으로 호출할 수 없습니다).
2.1, 특정 항목에서 하위 항목을 아래쪽으로 탐색합니다. node 노드, 임시 테이블 데이터를 재귀적으로 생성
-- pro_cre_childlist DELIMITER $$ DROP PROCEDURE IF EXISTS csdn.pro_cre_childlist$$ CREATE PROCEDURE csdn.pro_cre_childlist(IN rootId INT,IN nDepth INT) BEGIN DECLARE done INT DEFAULT 0; DECLARE b INT; DECLARE cur1 CURSOR FOR SELECT id FROM channel WHERE parent_id=rootId; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; SET max_sp_recursion_depth=12; INSERT INTO tmpLst VALUES (NULL,rootId,nDepth); OPEN cur1; FETCH cur1 INTO b; WHILE done=0 DO CALL pro_cre_childlist(b,nDepth+1); FETCH cur1 INTO b; END WHILE; CLOSE cur1; END$$
2.2, 노드에서 루트 노드까지 상향 추적하고, 임시 테이블 데이터를 재귀적으로 생성
2.3, Oracle SYS_CONNECT_BY_PATH와 유사한 기능을 구현하고 재귀 프로세스가 노드 ID 경로를 출력합니다.
2.4, 재귀 프로세스는 노드 이름 경로를 출력합니다
-- pro_cre_pnlist DELIMITER $$ USE csdn$$ DROP PROCEDURE IF EXISTS pro_cre_pnlist$$ CREATE PROCEDURE pro_cre_pnlist(IN nid INT,IN delimit VARCHAR(10),INOUT pathstr VARCHAR(1000)) BEGIN DECLARE done INT DEFAULT 0; DECLARE parentid INT DEFAULT 0; DECLARE cur1 CURSOR FOR SELECT t.parent_id,CONCAT(t.cname,delimit,pathstr) FROM channel AS t WHERE t.id = nid; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; SET max_sp_recursion_depth=12; OPEN cur1; FETCH cur1 INTO parentid,pathstr; WHILE done=0 DO CALL pro_cre_pnlist(parentid,delimit,pathstr); FETCH cur1 INTO parentid,pathstr; END WHILE; CLOSE cur1; END$$ DELIMITER ;
2.5,调用函数输出id路径
-- fn_tree_path DELIMITER $$ DROP FUNCTION IF EXISTS csdn.fn_tree_path$$ CREATE FUNCTION csdn.fn_tree_path(nid INT,delimit VARCHAR(10)) RETURNS VARCHAR(2000) CHARSET utf8 BEGIN DECLARE pathid VARCHAR(1000); SET @pathid=CAST(nid AS CHAR); CALL pro_cre_pathlist(nid,delimit,@pathid); RETURN @pathid; END$$
2.6,调用函数输出name路径
-- fn_tree_pathname -- 调用函数输出name路径 DELIMITER $$ DROP FUNCTION IF EXISTS csdn.fn_tree_pathname$$ CREATE FUNCTION csdn.fn_tree_pathname(nid INT,delimit VARCHAR(10)) RETURNS VARCHAR(2000) CHARSET utf8 BEGIN DECLARE pathid VARCHAR(1000); SET @pathid=''; CALL pro_cre_pnlist(nid,delimit,@pathid); RETURN @pathid; END$$ DELIMITER ;
2.7,调用过程输出子节点
-- pro_show_childLst DELIMITER $$ -- 调用过程输出子节点 DROP PROCEDURE IF EXISTS pro_show_childLst$$ CREATE PROCEDURE pro_show_childLst(IN rootId INT) BEGIN DROP TEMPORARY TABLE IF EXISTS tmpLst; CREATE TEMPORARY TABLE IF NOT EXISTS tmpLst (sno INT PRIMARY KEY AUTO_INCREMENT,id INT,depth INT); CALL pro_cre_childlist(rootId,0); SELECT channel.id,CONCAT(SPACE(tmpLst.depth*2),'--',channel.cname) NAME,channel.parent_id,tmpLst.depth,fn_tree_path(channel.id,'/') path, fn_tree_pathname(channel.id,'/') pathname FROM tmpLst,channel WHERE tmpLst.id=channel.id ORDER BY tmpLst.sno; END$$
2.8,调用过程输出父节点
-- pro_show_parentLst DELIMITER $$ -- 调用过程输出父节点 DROP PROCEDURE IF EXISTS `pro_show_parentLst`$$ CREATE PROCEDURE `pro_show_parentLst`(IN rootId INT) BEGIN DROP TEMPORARY TABLE IF EXISTS tmpLst; CREATE TEMPORARY TABLE IF NOT EXISTS tmpLst (sno INT PRIMARY KEY AUTO_INCREMENT,id INT,depth INT); CALL pro_cre_parentlist(rootId,0); SELECT channel.id,CONCAT(SPACE(tmpLst.depth*2),'--',channel.cname) NAME,channel.parent_id,tmpLst.depth, fn_tree_path(channel.id,'/') path,fn_tree_pathname(channel.id,'/') pathname FROM tmpLst,channel WHERE tmpLst.id=channel.id ORDER BY tmpLst.sno; END$$
3,开始测试:
3.1,从根节点开始显示,显示子节点集合:
mysql> CALL pro_show_childLst(-1); +----+-----------------------+-----------+-------+-------------+----------------------------+ | id | NAME | parent_id | depth | path | pathname | +----+-----------------------+-----------+-------+-------------+----------------------------+ | 13 | --首页 | -1 | 1 | -1/13 | 首页/ | | 16 | --左上幻灯片 | 13 | 2 | -1/13/16 | 首页/左上幻灯片/ | | 14 | --TV580 | -1 | 1 | -1/14 | TV580/ | | 17 | --帮忙 | 14 | 2 | -1/14/17 | TV580/帮忙/ | | 18 | --栏目简介 | 17 | 3 | -1/14/17/18 | TV580/帮忙/栏目简介/ | | 15 | --生活580 | -1 | 1 | -1/15 | 生活580/ | +----+-----------------------+-----------+-------+-------------+----------------------------+ 6 rows in set (0.05 sec) Query OK, 0 rows affected (0.05 sec)
3.2,显示首页下面的子节点
CALL pro_show_childLst(13); mysql> CALL pro_show_childLst(13); +----+---------------------+-----------+-------+----------+-------------------------+ | id | NAME | parent_id | depth | path | pathname | +----+---------------------+-----------+-------+----------+-------------------------+ | 13 | --首页 | -1 | 0 | -1/13 | 首页/ | | 16 | --左上幻灯片 | 13 | 1 | -1/13/16 | 首页/左上幻灯片/ | +----+---------------------+-----------+-------+----------+-------------------------+ 2 rows in set (0.02 sec) Query OK, 0 rows affected (0.02 sec) mysql>
3.3,显示TV580下面的所有子节点
CALL pro_show_childLst(14); mysql> CALL pro_show_childLst(14); +----+--------------------+-----------+-------+-------------+----------------------------+ | id | NAME | parent_id | depth | path | pathname | +----+--------------------+-----------+-------+-------------+----------------------------+ | 14 | --TV580 | -1 | 0 | -1/14 | TV580/ | | 17 | --帮忙 | 14 | 1 | -1/14/17 | TV580/帮忙/ | | 18 | --栏目简介 | 17 | 2 | -1/14/17/18 | TV580/帮忙/栏目简介/ | +----+--------------------+-----------+-------+-------------+----------------------------+ 3 rows in set (0.02 sec) Query OK, 0 rows affected (0.02 sec) mysql>
3.4,“帮忙”节点有一个子节点,显示出来:
CALL pro_show_childLst(17); mysql> CALL pro_show_childLst(17); +----+------------------+-----------+-------+-------------+----------------------------+ | id | NAME | parent_id | depth | path | pathname | +----+------------------+-----------+-------+-------------+----------------------------+ | 17 | --帮忙 | 14 | 0 | -1/14/17 | TV580/帮忙/ | | 18 | --栏目简介 | 17 | 1 | -1/14/17/18 | TV580/帮忙/栏目简介/ | +----+------------------+-----------+-------+-------------+----------------------------+ 2 rows in set (0.03 sec) Query OK, 0 rows affected (0.03 sec) mysql>
3.5,“栏目简介”没有子节点,所以只显示最终节点:
mysql> CALL pro_show_childLst(18); +----+----------------+-----------+-------+-------------+----------------------------+ | id | NAME | parent_id | depth | path | pathname | +----+----------------+-----------+-------+-------------+----------------------------+ | 18 | --栏目简介 | 17 | 0 | -1/14/17/18 | TV580/帮忙/栏目简介/ | +----+----------------+-----------+-------+-------------+----------------------------+ 1 row in set (0.36 sec) Query OK, 0 rows affected (0.36 sec) mysql>
3.6,显示根节点的父节点
CALL pro_show_parentLst(-1); mysql> CALL pro_show_parentLst(-1); Empty set (0.01 sec) Query OK, 0 rows affected (0.01 sec) mysql>
3.7,显示“首页”的父节点
CALL pro_show_parentLst(13); mysql> CALL pro_show_parentLst(13); +----+----------+-----------+-------+-------+----------+ | id | NAME | parent_id | depth | path | pathname | +----+----------+-----------+-------+-------+----------+ | 13 | --首页 | -1 | 0 | -1/13 | 首页/ | +----+----------+-----------+-------+-------+----------+ 1 row in set (0.02 sec) Query OK, 0 rows affected (0.02 sec) mysql>
3.8,显示“TV580”的父节点,parent_id为-1
CALL pro_show_parentLst(14); mysql> CALL pro_show_parentLst(14); +----+---------+-----------+-------+-------+----------+ | id | NAME | parent_id | depth | path | pathname | +----+---------+-----------+-------+-------+----------+ | 14 | --TV580 | -1 | 0 | -1/14 | TV580/ | +----+---------+-----------+-------+-------+----------+ 1 row in set (0.02 sec) Query OK, 0 rows affected (0.02 sec)
3.9,显示“帮忙”节点的父节点
mysql> CALL pro_show_parentLst(17); mysql> CALL pro_show_parentLst(17); +----+-----------+-----------+-------+----------+---------------+ | id | NAME | parent_id | depth | path | pathname | +----+-----------+-----------+-------+----------+---------------+ | 17 | --帮忙 | 14 | 0 | -1/14/17 | TV580/帮忙/ | | 14 | --TV580 | -1 | 1 | -1/14 | TV580/ | +----+-----------+-----------+-------+----------+---------------+ 2 rows in set (0.02 sec) Query OK, 0 rows affected (0.02 sec) mysql>
3.10,显示最低层节点“栏目简介”的父节点
CALL pro_show_parentLst(18); mysql> CALL pro_show_parentLst(18); +----+----------------+-----------+-------+-------------+----------------------------+ | id | NAME | parent_id | depth | path | pathname | +----+----------------+-----------+-------+-------------+----------------------------+ | 18 | --栏目简介 | 17 | 0 | -1/14/17/18 | TV580/帮忙/栏目简介/ | | 17 | --帮忙 | 14 | 1 | -1/14/17 | TV580/帮忙/ | | 14 | --TV580 | -1 | 2 | -1/14 | TV580/ | +----+----------------+-----------+-------+-------------+----------------------------+ 3 rows in set (0.02 sec) Query OK, 0 rows affected (0.02 sec) mysql>
以上就是MySQL 实现树形的遍历(关于多级菜单栏以及多级上下部门的查询问题) 的内容,更多相关内容请关注PHP中文网(www.php.cn)!