一个PHP程序员的个人博客-司空如风

MySQL树形结构的数据库表设计和查询

1、邻接表(Adjacency List)

方案一、(Adjacency List)只存储当前节点的父节点信息。


  -- 2018-8-11 MySQL树结构 --
    -- Author: xielong  Email:cnxielong@gmail.com --
    
     -- 建表 --
     DROP TABLE  IF EXISTS Employees;
    
     CREATE TABLE IF NOT EXISTS Employees (
      id INT AUTO_INCREMENT,
      ename VARCHAR (100),
      job VARCHAR (100),
      parent_id INT,
      PRIMARY KEY(id)
    ) ENGINE = INNODB DEFAULT CHARSET = UTF8;
    
    
    DESCRIBE Employees
    
    
    -- 插入数据 --
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('老王','高管','0');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('老宋','产品部主管','1');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('老牛','高管','1');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('小吴','高管','2');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('小李','高管','2');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('小欢','高管','3');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('小小','高管','3');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('小天','高管','4');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('肖丽','高管','4');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('十号','高管','5');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('十一号','高管','5');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('十二号','高管','6');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('十三号','高管','6');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('十四号','高管','7');
    INSERT INTO `employees` ( `ename`, `job`, `parent_id`) VALUES('小黑十五','高管','7');
    

 -- 查询小天的上级Id  隐式内连接 关键条件父节点 --
 SELECT e2.id, e2.ename, e2.job FROM Employees e1, Employees e2 WHERE e1.`parent_id` = e2.id AND e1.id=8
 
 -- 查询小天的上级Id  显示内连接 关键条件父节点 --
 SELECT e2.id, e2.ename, e2.job FROM Employees e1 INNER JOIN Employees e2 WHERE e1.`parent_id` = e2.id AND e1.id=8

    -- 查询老宋管理下的直属员工:隐式内连接 关键条件父子节点 老宋ID=2 --
    SELECT e2.id, e2.ename, e2.job FROM Employees e1, Employees e2 WHERE e1.id=2 AND e2.`parent_id` = e1.id
    
    -- 查询小天的上级Id  显示内连接 关键条件父子节点 老宋.ename='老宋' --
    SELECT e2.id, e2.ename, e2.job FROM Employees e1 INNER JOIN Employees e2 WHERE e2.`parent_id` = e1.id AND e1.ename='老宋'

    --  1、查询小天的所有上级 --
    
    -- 删除 --
       DROP FUNCTION IF EXISTS getSuperiors; 
    
    -- 创建 -- 
    DELIMITER $$
    
    CREATE DEFINER=`root`@`localhost` FUNCTION `getSuperiors` (`uid` INT) RETURNS VARCHAR(1000) 
    BEGIN
        DECLARE superiors VARCHAR(1000) DEFAULT '';
        DECLARE sTemp INTEGER DEFAULT uid;
        DECLARE tmpName VARCHAR(20);
    
        WHILE (sTemp>0) DO
            SELECT parent_id INTO sTemp FROM employees WHERE id = sTemp;
            SELECT ename INTO tmpName FROM employees WHERE id = sTemp;
            IF(sTemp>0)THEN
                SET superiors = CONCAT(tmpName,',',superiors);
            END IF;
        END WHILE;
            SET superiors = LEFT(superiors,CHARACTER_LENGTH(superiors)-1);
        RETURN superiors;
    END $$
    
    -- 调用 --
    SELECT   getSuperiors(8) 上司;

思路如下:先获取所有父节点为老王id的员工id,然后将员工姓名加入结果列表里,在调用一个神奇的查找函数,即可进行神奇的查找:


    --  查询老王管理的所有员工 --
    
    -- 删除 --
       DROP PROCEDURE IF EXISTS getSubordinate 
    
    -- 创建 -- 
       DELIMITER $$
    
    CREATE DEFINER = `root` @`localhost` FUNCTION `getSubordinate` (`uid` INT) RETURNS VARCHAR (2000)
    BEGIN
      DECLARE str VARCHAR (1000);
      DECLARE cid VARCHAR (100);
      DECLARE result VARCHAR (1000);
      DECLARE tmpName VARCHAR (100);
      SET str = '$';
      SET cid = CAST(uid AS CHAR(10));
      WHILE
        cid IS NOT NULL DO 
        SET str = CONCAT(str, ',', cid);
        SELECT  GROUP_CONCAT(id) INTO cid  FROM  employees  WHERE FIND_IN_SET(parent_id, cid);
      END WHILE;
      SELECT
        GROUP_CONCAT(ename) INTO result   FROM  employees  WHERE FIND_IN_SET(parent_id, str);
      RETURN result;
    END $$
    
    -- 调用 --
    SELECT   getSubordinate(1)

2、继承关系驱动的设计表和基于左右值编码的设计

参考链接: https://blog.csdn.net/lj1314ailj/article/details/52074216

参考:MySQL 实现树形的遍历

参考链接: https://blog.csdn.net/mchdba/article/details/39277301


作者:X-Dragon烟雨任平生
来源:CSDN
原文:https://blog.csdn.net/xielong0509/article/details/81592934

当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »