ホームページ データベース 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 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Windows 11: スタート レイアウトをインポートおよびエクスポートする簡単な方法 Windows 11: スタート レイアウトをインポートおよびエクスポートする簡単な方法 Aug 22, 2023 am 10:13 AM

Windows 11 では、スタート メニューが再設計され、スタート メニューにフォルダー、アプリ、アプリがあった以前のバージョンとは異なり、ページのグリッドに配置された簡略化されたアプリのセットが特徴です。 [スタート] メニューのレイアウトをカスタマイズし、他の Windows デバイスにインポートおよびエクスポートして、好みに合わせてカスタマイズできます。このガイドでは、スタート レイアウトをインポートして Windows 11 のデフォルト レイアウトをカスタマイズする手順について説明します。 Windows 11 の Import-StartLayout とは何ですか? Import Start Layout は、Windows 10 以前のバージョンでスタート メニューのカスタマイズをインポートするために使用されるコマンドレットです。

Windows 11の右クリックメニューで「その他のオプションを表示」をデフォルトにする方法 Windows 11の右クリックメニューで「その他のオプションを表示」をデフォルトにする方法 Jul 10, 2023 pm 12:33 PM

私たちユーザーが決して望んでいない最も迷惑な変更の 1 つは、右クリックのコンテキスト メニューに [その他のオプションを表示] が含まれていることです。ただし、これを削除して、Windows 11 のクラシック コンテキスト メニューに戻すことができます。複数回クリックしたり、コンテキスト メニューで ZIP ショートカットを探したりする必要はもうありません。 Windows 11 で本格的な右クリック コンテキスト メニューに戻るには、このガイドに従ってください。解決策 1 – CLSID を手動で調整する これは、リストにある唯一の手動方法です。この問題を解決するには、レジストリ エディターで特定のキーまたは値を調整します。注 – このようなレジストリの編集は非常に安全であり、問​​題なく機能します。したがって、システムでこれを試す前に、レジストリのバックアップを作成する必要があります。ステップ 1 – 試してみる

iPhoneでメッセージを編集する方法 iPhoneでメッセージを編集する方法 Dec 18, 2023 pm 02:13 PM

iPhone のネイティブ メッセージ アプリを使用すると、送信されたテキストを簡単に編集できます。このようにして、間違いや句読点を修正したり、テキストに適用された可能性のある間違った語句や単語を自動修正したりすることができます。この記事では、iPhone でメッセージを編集する方法を学びます。 iPhone でメッセージを編集する方法 必須: iOS16 以降を実行している iPhone。 iMessage テキストはメッセージ アプリでのみ編集でき、元のテキストを送信してから 15 分以内に限り編集できます。 iMessage 以外のテキストはサポートされていないため、取得または編集できません。 iPhone でメッセージ アプリを起動します。 [メッセージ] で、メッセージを編集する会話を選択します

Windows 11の右クリックコンテキストメニューから「Windowsターミナルで開く」オプションを削除する方法 Windows 11の右クリックコンテキストメニューから「Windowsターミナルで開く」オプションを削除する方法 Apr 13, 2023 pm 06:28 PM

デフォルトでは、Windows 11 の右クリック コンテキスト メニューには [Windows ターミナルで開く] というオプションがあります。これは、ユーザーが特定の場所で Windows ターミナルを開くことができる非常に便利な機能です。たとえば、フォルダーを右クリックして [Windows ターミナルで開く] オプションを選択すると、Windows ターミナルが起動し、その特定の場所が現在の作業ディレクトリとして設定されます。これは素晴らしい機能ですが、誰もがこの機能を活用できるわけではありません。一部のユーザーは、右クリック コンテキスト メニューにこのオプションを入れたくないため、右クリック コンテキスト メニューを整理するために削除したいと考えている場合があります。

純粋な CSS を使用して影付きのメニュー ナビゲーション バーを実装する実装手順 純粋な CSS を使用して影付きのメニュー ナビゲーション バーを実装する実装手順 Oct 16, 2023 am 08:27 AM

純粋な CSS を使用して影付きのメニュー ナビゲーション バーを実装する手順には、特定のコード サンプルが必要です。Web デザインでは、メニュー ナビゲーション バーは非常に一般的な要素です。メニュー ナビゲーション バーに影効果を追加すると、外観が向上するだけでなく、ユーザー エクスペリエンスも向上します。この記事では、純粋な CSS を使用して影付きのメニュー ナビゲーション バーを実装し、参考として具体的なコード例を示します。実装手順は次のとおりです。 HTML 構造の作成 まず、メニュー ナビゲーション バーを収容するための基本的な HTML 構造を作成する必要があります。による

Windows 11 で [その他のオプションを表示] メニューを無効にする方法 Windows 11 で [その他のオプションを表示] メニューを無効にする方法 Apr 13, 2023 pm 08:10 PM

新しく改良された Microsoft オペレーティング システムを体験する人が増えていますが、それでも昔ながらのデザインを好む人もいるようです。新しいコンテキスト メニューが Windows 11 に優れた一貫性をもたらしていることは疑いの余地がありません。 Windows 10 について考えてみると、各アプリケーションに独自のコンテキスト メニュー要素があるという事実が、一部の人にとって深刻な混乱を引き起こします。 Windows 11 の透明なタスクバーから丸い角に至るまで、このオペレーティング システムは傑作です。この問題では、世界中のユーザーが Windows 11 の「その他のオプションの表示」メニューをすばやく無効にする方法を知りたいと考えています。プロセスは非常に簡単なので、同じ状況にある場合は、必ず最後まで確認してください。

5 つの簡単なステップで Windows 11 で広告を拒否する方法 5 つの簡単なステップで Windows 11 で広告を拒否する方法 Apr 22, 2023 pm 07:16 PM

広告が時々煩わしい場合があることは誰もが知っています。広告が最も歓迎されないタイミングでどのように表示されるのか、広告が望ましくないプラットフォームにどのように誘導するのか、そして最悪の場合、一部の広告はマルウェアの脅威をもたらすことが知られています。 Windows 11 の絶え間ない広告を削除する方法を知りたいが、その方法が分からなかった場合は、ここが待ち望んでいた助けです。この記事の内容 Windows 11 で広告が表示されるのはなぜですか? Windows 11 の広告を取り除くことが緊急に必要であるにもかかわらず、これらの広告が表示される原因と表示される理由を理解することは価値があると考えています。 最近の Windows アップデートで追加された機能 - ニュースや興味などの機能がないと、通知を受け取ることが困難になる場合があります。コンピューターを使用してください。これ

純粋な CSS を使用してメニュー ナビゲーション バーのフローティング効果を実装する手順 純粋な CSS を使用してメニュー ナビゲーション バーのフローティング効果を実装する手順 Oct 19, 2023 am 10:13 AM

純粋な CSS を使用してメニュー ナビゲーション バーのフローティング効果を実装する手順 Web デザインの継続的な進歩に伴い、Web サイトに対するユーザーの要求はますます高くなっています。より良いユーザーエクスペリエンスを提供するために、サスペンション効果はウェブサイトのデザインで広く使用されています。この記事では、純粋な CSS を使用してメニュー ナビゲーション バーのフローティング効果を実現し、Web サイトの使いやすさと美しさを向上させる方法を紹介します。基本的なメニュー構造を作成する まず、HTML ドキュメント内にメニューの基本構造を作成する必要があります。簡単な例を次に示します: <navclass=&q

See all articles