1、鄰接表(Adjacency List)
- 實例:現在有一個要存儲一下公司的人員結構,大致層次結構如下:
那么怎么存儲這個結構?並且要獲取以下信息:
- 1.查詢小天的直接上司。
- 2.查詢老宋管理下的直屬員工。
- 3.查詢小天的所有上司。
- 4.查詢老王管理的所有員工。
1 方案一、(Adjacency List)只存儲當前節點的父節點信息。 2 -- 2018-8-11 MySQL樹結構 -- 3 -- Author: xielong Email:cnxielong@gmail.com -- 4 5 -- 建表 -- 6 DROP TABLE IF EXISTS Employees; 7 8 CREATE TABLE IF NOT EXISTS Employees ( 9 id INT AUTO_INCREMENT, 10 ename VARCHAR (100), 11 job VARCHAR (100), 12 parent_id INT, 13 PRIMARY KEY(id) 14 ) ENGINE = INNODB DEFAULT CHARSET = UTF8; 15 16 17 DESCRIBE Employees 18 19 20 -- 插入數據 -- 21 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('老王','高管','0'); 22 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('老宋','產品部主管','1'); 23 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('老牛','高管','1'); 24 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('小吳','高管','2'); 25 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('小李','高管','2'); 26 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('小歡','高管','3'); 27 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('小小','高管','3'); 28 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('小天','高管','4'); 29 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('肖麗','高管','4'); 30 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('十號','高管','5'); 31 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('十一號','高管','5'); 32 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('十二號','高管','6'); 33 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('十三號','高管','6'); 34 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('十四號','高管','7'); 35 INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('小黑十五','高管','7');
數據庫結構信息:
-
好的,現在開始進入回答環節:
- 1.查詢小天的直接上司:
1 -- 查詢小天的上級Id 隱式內連接 關鍵條件父節點 -- 2 SELECT e2.id, e2.ename, e2.job FROM Employees e1, Employees e2 WHERE e1.`parent_id` = e2.id AND e1.id=8 3 4 -- 查詢小天的上級Id 顯示內連接 關鍵條件父節點 -- 5 SELECT e2.id, e2.ename, e2.job FROM Employees e1 INNER JOIN Employees e2 WHERE e1.`parent_id` = e2.id AND e1.id=8
2.查詢老宋管理下的直屬員工:
1 -- 查詢老宋管理下的直屬員工:隱式內連接 關鍵條件父子節點 老宋ID=2 -- 2 SELECT e2.id, e2.ename, e2.job FROM Employees e1, Employees e2 WHERE e1.id=2 AND e2.`parent_id` = e1.id 3 4 -- 查詢小天的上級Id 顯示內連接 關鍵條件父子節點 老宋.ename='老宋' -- 5 SELECT e2.id, e2.ename, e2.job FROM Employees e1 INNER JOIN Employees e2 WHERE e2.`parent_id` = e1.id AND e1.ename='老宋'
3.查詢小天的所有上司。
- 這里肯定沒法直接查,只能用循環進行循環查詢,先查直接上司,再查直接上司的直接上司,依次循環,這樣麻煩的事情,還是得先建立一個存儲過程:
- 睜大眼睛看仔細了,接下來是騷操作環節:
1 -- 1、查詢小天的所有上級 -- 2 3 -- 刪除 -- 4 DROP FUNCTION IF EXISTS getSuperiors; 5 6 -- 創建 -- 7 DELIMITER $$ 8 9 CREATE DEFINER=`root`@`localhost` FUNCTION `getSuperiors` (`uid` INT) RETURNS VARCHAR(1000) 10 BEGIN 11 DECLARE superiors VARCHAR(1000) DEFAULT ''; 12 DECLARE sTemp INTEGER DEFAULT uid; 13 DECLARE tmpName VARCHAR(20); 14 15 WHILE (sTemp>0) DO 16 SELECT parent_id INTO sTemp FROM employees WHERE id = sTemp; 17 SELECT ename INTO tmpName FROM employees WHERE id = sTemp; 18 IF(sTemp>0)THEN 19 SET superiors = CONCAT(tmpName,',',superiors); 20 END IF; 21 END WHILE; 22 SET superiors = LEFT(superiors,CHARACTER_LENGTH(superiors)-1); 23 RETURN superiors; 24 END $$ 25 26 -- 調用 -- 27 SELECT getSuperiors(8) 上司;
-
這一段存儲過程可以查詢子節點的所有父節點,來試驗一下
-
好的,騷操作完成。
-
顯然,這樣。獲取子節點的全部父節點的時候很麻煩。。
4.查詢老王管理的所有員工。
思路如下:先獲取所有父節點為老王id的員工id,然后將員工姓名加入結果列表里,在調用一個神奇的查找函數,即可進行神奇的查找:
1 -- 查詢老王管理的所有員工 -- 2 3 -- 刪除 -- 4 DROP PROCEDURE IF EXISTS getSubordinate 5 6 -- 創建 -- 7 DELIMITER $$ 8 9 CREATE DEFINER = `root` @`localhost` FUNCTION `getSubordinate` (`uid` INT) RETURNS VARCHAR (2000) 10 BEGIN 11 DECLARE str VARCHAR (1000); 12 DECLARE cid VARCHAR (100); 13 DECLARE result VARCHAR (1000); 14 DECLARE tmpName VARCHAR (100); 15 SET str = '$'; 16 SET cid = CAST(uid AS CHAR(10)); 17 WHILE 18 cid IS NOT NULL DO 19 SET str = CONCAT(str, ',', cid); 20 SELECT GROUP_CONCAT(id) INTO cid FROM employees WHERE FIND_IN_SET(parent_id, cid); 21 END WHILE; 22 SELECT 23 GROUP_CONCAT(ename) INTO result FROM employees WHERE FIND_IN_SET(parent_id, str); 24 RETURN result; 25 END $$ 26 27 -- 調用 -- 28 SELECT getSubordinate(1)
看神奇的結果:
-
雖然搞出來了,但說實話,真是不容易。。。
-
這種方法的優點是存儲的信息少,查直接上司和直接下屬的時候很方便,缺點是多級查詢的時候很費勁。所以當只需要用到直接上下級關系的時候,用這種方法還是不錯的,可以節省很多空間。
2、繼承關系驅動的設計表和基於左右值編碼的設計
參考鏈接: https://blog.csdn.net/lj1314ailj/article/details/52074216
參考:MySQL 實現樹形的遍歷
MySQL 實現樹形的遍歷(關於多級菜單欄以及多級上下部門的查詢問題)
參考鏈接: https://blog.csdn.net/mchdba/article/details/39277301 ---------------------