首页 数据库 mysql教程 实现树形的遍历(关于多级菜单栏以及多级上下部门的查询问题)_MySQL

实现树形的遍历(关于多级菜单栏以及多级上下部门的查询问题)_MySQL

May 30, 2016 pm 05:11 PM
上下 菜单

前言:

        关于多级别菜单栏或者权限系统中部门上下级的树形遍历,oracle中有connect by来实现,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,从某节点向下遍历子节点,递归生成临时表数据

-- 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,从某节点向上追溯根节点,递归生成临时表数据

-- pro_cre_parentlist
DELIMITER $$
DROP PROCEDURE IF EXISTS csdn.pro_cre_parentlist$$   
CREATE PROCEDURE csdn.pro_cre_parentlist(IN rootId INT,IN nDepth INT)   
BEGIN   
      DECLARE done INT DEFAULT 0;   
      DECLARE b INT;   
      DECLARE cur1 CURSOR FOR SELECT parent_id FROM channel WHERE 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_parentlist(b,nDepth+1);   
              FETCH cur1 INTO b;   
      END WHILE;   
       
      CLOSE cur1;   
     END$$   
登录后复制

2.3,实现类似Oracle SYS_CONNECT_BY_PATH的功能,递归过程输出某节点id路径

-- pro_cre_pathlist
DELIMITER $$
USE csdn$$
DROP PROCEDURE IF EXISTS pro_cre_pathlist$$
CREATE PROCEDURE pro_cre_pathlist(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(CAST(t.parent_id AS CHAR),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_pathlist(parentid,delimit,pathstr);   
              FETCH cur1 INTO parentid,pathstr;   
      END WHILE;   
            
      CLOSE cur1;    
END$$


DELIMITER ;
登录后复制

2.4,递归过程输出某节点name路径

-- 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>
登录后复制

 


本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
2 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
2 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Windows 11: 导入和导出开始布局的简便方法 Windows 11: 导入和导出开始布局的简便方法 Aug 22, 2023 am 10:13 AM

在Windows11中,“开始”菜单经过重新设计,并具有一组简化的应用,这些应用排列在页面网格中,这与它的前身不同,后者在“开始”菜单上有文件夹、应用和组。您可以自定义“开始”菜单布局,并将其导入并导出到其他Windows设备,以根据您的喜好对其进行个性化设置。在本指南中,我们将讨论在Windows11上导入开始布局以自定义默认布局的分步说明。什么是Windows11中的Import-StartLayout?导入开始布局是Windows10和更早版本中使用的cmdlet,用于将“开始”菜单的自定

如何在Windows 11的右键单击菜单中默认“显示更多选项” 如何在Windows 11的右键单击菜单中默认“显示更多选项” Jul 10, 2023 pm 12:33 PM

我们用户从来不想要的最烦人的更改之一是在右键单击上下文菜单中包含“显示更多选项”。但是,您可以删除它并取回Windows11中的经典上下文菜单。不再需要多次单击并在上下文菜单中查找这些ZIP快捷方式。按照本指南返回Windows11上成熟的右键单击上下文菜单。修复1–手动调整CLSID这是我们列表中唯一的手动方法。您将在注册表编辑器中调整特定键或值以解决此问题。注意–像这样的注册表编辑非常安全,并且可以正常工作。因此,在系统上尝试此操作之前,您应该创建注册表备份。步骤1–尝试

如何在iPhone上编辑消息 如何在iPhone上编辑消息 Dec 18, 2023 pm 02:13 PM

iPhone上的原生“信息”应用可让您轻松编辑已发送的文本。这样,您可以纠正您的错误、标点符号,甚至是自动更正可能已应用于您的文本的错误短语/单词。在这篇文章中,我们将了解如何在iPhone上编辑消息。如何在iPhone上编辑消息必需:运行iOS16或更高版本的iPhone。您只能在“消息”应用程序上编辑iMessage文本,并且只能在发送原始文本后的15分钟内编辑。不支持非iMessage信息文本,因此无法检索或编辑它们。在iPhone上启动消息应用程序。在“信息”中,选择要从中编辑消息的对话

纯CSS实现带阴影效果的菜单导航栏的实现步骤 纯CSS实现带阴影效果的菜单导航栏的实现步骤 Oct 16, 2023 am 08:27 AM

纯CSS实现带阴影效果的菜单导航栏的实现步骤,需要具体代码示例在网页设计中,菜单导航栏是一个非常常见的元素。通过给菜单导航栏添加阴影效果,不仅可以增加其美观度,还可以提升用户体验。在本文中,我们将使用纯CSS来实现一个带阴影效果的菜单导航栏,并提供具体的代码示例供参考。实现步骤如下:创建HTML结构首先,我们需要创建一个基本的HTML结构来容纳菜单导航栏。以

如何从 Windows 11 中的右键单击上下文菜单中删除“在 Windows 终端中打开”选项 如何从 Windows 11 中的右键单击上下文菜单中删除“在 Windows 终端中打开”选项 Apr 13, 2023 pm 06:28 PM

默认情况下,Windows 11 右键单击​​上下文菜单有一个名为Open in Windows Terminal的选项。这是一个非常有用的功能,允许用户在特定位置打开 Windows 终端。例如,如果您右键单击一个文件夹并选择“在 Windows 终端中打开”选项,则 Windows 终端将启动并将该特定位置设置为其当前工作目录。尽管这是一个了不起的功能,但并不是每个人都发现此功能的用途。一些用户可能只是不希望在他们的右键单击上下文菜单中使用此选项,并且希望将其删除以整理他们的右键单击上下文菜

如何禁用 Windows 11 的“显示更多选项”菜单 如何禁用 Windows 11 的“显示更多选项”菜单 Apr 13, 2023 pm 08:10 PM

越来越多的人正在体验新的和改进的微软操作系统,但似乎他们中的一些人仍然更喜欢老式的设计。毫无疑问,新的上下文菜单为 Windows 11 带来了令人印象深刻的一致性。如果我们考虑 Windows 10,每个应用程序都有自己的上下文菜单元素这一事实给某些人造成了严重的混乱。从Windows 11 透明任务栏到圆角,这款操作系统堪称杰作。在这件事上,全球用户有兴趣了解如何快速禁用 Windows 11 Show More Options 菜单。这个过程非常简单,所以如果您在同一条船上,请确保您完全查

如何在Windows 11中通过5个简单步骤拒绝广告 如何在Windows 11中通过5个简单步骤拒绝广告 Apr 22, 2023 pm 07:16 PM

我们都知道广告有时会很烦人。广告如何在最不受欢迎的时候弹出;他们如何将您引导至不需要的平台;最糟糕的是,已知某些广告会构成恶意软件威胁。因此,如果您一直想知道如何摆脱不断的Windows11广告但不知道如何,这是您一直在等待的帮助。在本文中为什么我在Windows11中会收到广告?尽管迫切需要摆脱Windows11广告,但我们认为值得了解触发这些广告的原因以及您获得它们的原因:从最近的Windows更新中添加的功能-新闻和兴趣等功能可能会使在不发送通知的情况下难以使用你的电脑。此

JavaScript 如何实现图片的上下拖动切换效果? JavaScript 如何实现图片的上下拖动切换效果? Oct 18, 2023 am 09:09 AM

JavaScript如何实现图片的上下拖动切换效果?随着互联网的发展,图片在我们生活和工作中扮演着重要的角色。为了提升用户体验,我们常常需要给图片增加一些特效或交互效果。其中,图片的上下拖动切换效果是一种很常见、简洁且实用的效果。本文将介绍如何使用JavaScript实现这一效果,并提供具体的代码示例。首先,我们需要创建一个HTML文件,来展示图片并实现拖

See all articles