MySQL樹形結構的數據庫表設計和查詢

一、鄰接表(Adjacency List)

  • 實例:如今有一個要存儲一下公司的人員結構,大體層次結構以下:

員工

那麼怎麼存儲這個結構?而且要獲取如下信息:數據庫

  • 1.查詢小天的直接上司。
  • 2.查詢老宋管理下的直屬員工。
  • 3.查詢小天的全部上司。
  • 4.查詢老王管理的全部員工。
 1 方案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');

數據庫結構信息:函數

數據庫信息

  • 好的,如今開始進入回答環節:ui

  • 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.查詢小天的全部上司。spa

  • 這裏確定無法直接查,只能用循環進行循環查詢,先查直接上司,再查直接上司的直接上司,依次循環,這樣麻煩的事情,仍是得先創建一個存儲過程:
  • 睜大眼睛看仔細了,接下來是騷操做環節:
 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) 上司;

 

  • 這一段存儲過程能夠查詢子節點的全部父節點,來試驗一下 .net

  • 好的,騷操做完成。設計

  • 顯然,這樣。獲取子節點的所有父節點的時候很麻煩。。3d

這裏寫圖片描述

4.查詢老王管理的全部員工。code

  思路以下:先獲取全部父節點爲老王id的員工id,而後將員工姓名加入結果列表裏,在調用一個神奇的查找函數,便可進行神奇的查找:blog

 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)

看神奇的結果:

這裏寫圖片描述  

  • 雖然搞出來了,但說實話,真是不容易。。。

  • 這種方法的優勢是存儲的信息少,查直接上司和直接下屬的時候很方便,缺點是多級查詢的時候很費勁。因此當只須要用到直接上下級關係的時候,用這種方法仍是不錯的,能夠節省不少空間。

二、繼承關係驅動的設計表和基於左右值編碼的設計

參考連接: https://blog.csdn.net/lj1314ailj/article/details/52074216

 

參考:MySQL 實現樹形的遍歷

MySQL 實現樹形的遍歷(關於多級菜單欄以及多級上下部門的查詢問題)

參考連接: https://blog.csdn.net/mchdba/article/details/39277301 ---------------------

相關文章
相關標籤/搜索