首頁 資料庫 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.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前 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–嘗試

如何從 Windows 11 中的右鍵單擊上下文功能表中刪除「在 Windows 終端機中開啟」選項 如何從 Windows 11 中的右鍵單擊上下文功能表中刪除「在 Windows 終端機中開啟」選項 Apr 13, 2023 pm 06:28 PM

預設情況下,Windows 11 右鍵單擊上下文功能表有一個名為Open in Windows Terminal的選項。這是一個非常有用的功能,可讓使用者在特定位置開啟 Windows 終端。例如,如果您右鍵單擊資料夾並選擇「在 Windows 終端機中開啟」選項,則 Windows 終端將啟動並將該特定位置設為其目前工作目錄。儘管這是一個了不起的功能,但並不是每個人都發現此功能的用途。一些用戶可能只是不希望在他們的右鍵單擊上下文功能表中使用此選項,並且希望將其刪除以整理他們的右鍵單擊上下文菜

如何在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 11 的「顯示更多選項」選單 Apr 13, 2023 pm 08:10 PM

越來越多的人正在體驗新的和改進的微軟作業系統,但似乎他們中的一些人仍然更喜歡老式的設計。毫無疑問,新的上下文功能表為 Windows 11 帶來了令人印象深刻的一致性。如果我們考慮 Windows 10,每個應用程式都有自己的上下文選單元素這一事實給某些人造成了嚴重的混亂。從Windows 11 透明工作列到圓角,這款作業系統堪稱傑作。在這件事上,全球用戶有興趣了解如何快速停用 Windows 11 Show More Options 選單。這個過程非常簡單,所以如果您在同一條船上,請確保您完全檢查

純CSS實現選單導覽列的懸浮效果的實現步驟 純CSS實現選單導覽列的懸浮效果的實現步驟 Oct 19, 2023 am 10:13 AM

純CSS實現選單導覽列的懸浮效果的實現步驟隨著Web設計的不斷進步,使用者對於網站的需求也越來越高。為了提供更好的使用者體驗,懸浮效果在網站設計中得到了廣泛應用。本文將介紹如何使用純CSS來實現選單導覽列的懸浮效果,以提升網站的可用性和美觀性。建立基本選單結構首先,我們需要在HTML文件中建立選單的基本結構。以下是一個簡單的範例:<navclass=&q

如何在Windows 11中透過5個簡單步驟拒絕廣告 如何在Windows 11中透過5個簡單步驟拒絕廣告 Apr 22, 2023 pm 07:16 PM

我們都知道廣告有時會很煩。廣告如何在最不受歡迎的時候彈出;他們如何將您引導至不需要的平台;最糟糕的是,已知某些廣告會構成惡意軟體威脅。因此,如果您一直想知道如何擺脫不斷的Windows11廣告但不知道如何,這是您一直在等待的幫助。在本文為什麼我會在Windows11中收到廣告?儘管迫切需要擺脫Windows11廣告,但我們認為值得了解觸發這些廣告的原因以及您獲得它們的原因:從最近的Windows更新中添加的功能-新聞和興趣等功能可能會使在不發送通知的情況下難以使用你的電腦。此

See all articles