【MySQL疑难杂症】如何将树形结构存储在数据库中(方案一、Adjacency List)
今天来看看一个比较头疼的问题,如何在数据库中存储树形结构呢?
像mysql这样的关系型数据库,比较适合存储一些类似表格的扁平化数据,但是遇到像树形结构这样有深度的人,就很难驾驭了。
举个栗子:现在有一个要存储一下公司的人员结构,大致层次结构如下:

(画个图真不容易。。)
那么怎么存储这个结构?并且要获取以下信息:
1.查询小天的直接上司。
2.查询老宋管理下的直属员工。
3.查询小天的所有上司。
4.查询老王管理的所有员工。
方案一、(Adjacency List)只存储当前节点的父节点信息。
CREATE TABLE Employees(
eid int,
ename VARCHAR(100),
position VARCHAR(100),
parent_id int
)
记录信息简单粗暴,那么现在存储一下这个结构信息:

好的,现在开始进入回答环节:
1.查询小天的直接上司:
SELECT e2.eid,e2.ename FROM employees e1,employees e2 WHERE e1.parent_id=e2.eid AND e1.ename='小天';

2.查询老宋管理下的直属员工:
SELECT e1.eid,e1.ename FROM employees e1,employees e2 WHERE e1.parent_id=e2.eid AND e2.ename='老宋';

3.查询小天的所有上司。
这里肯定没法直接查,只能用循环进行循环查询,先查直接上司,再查直接上司的直接上司,依次循环,这样麻烦的事情,还是得先建立一个存储过程:
睁大眼睛看仔细了,接下来是骚操作环节:
CREATE DEFINER=`root`@`localhost` FUNCTION `getSuperiors`(`uid` int) RETURNS varchar(1000) CHARSET gb2312
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 eid = sTemp;
SELECT ename into tmpName FROM employees where eid = 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
这一段存储过程可以查询子节点的所有父节点,来试验一下

好的,骚操作完成。
显然,这样。获取子节点的全部父节点的时候很麻烦。。
4.查询老王管理的所有员工。
思路如下:先获取所有父节点为老王id的员工id,然后将员工姓名加入结果列表里,在调用一个神奇的查找函数,即可进行神奇的查找:
CREATE DEFINER=`root`@`localhost` FUNCTION `getSubordinate`(`uid` int) RETURNS varchar(2000) CHARSET gb2312
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(eid) 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
看神奇的结果:

虽然搞出来了,但说实话,真是不容易。。。
这种方法的优点是存储的信息少,查直接上司和直接下属的时候很方便,缺点是多级查询的时候很费劲。所以当只需要用到直接上下级关系的时候,用这种方法还是不错的,可以节省很多空间。后续还会介绍其它存储方案,并没有绝对的优劣之分,适用场合不同而已。
本篇至此告一段落,欢迎大家继续关注。
【MySQL疑难杂症】如何将树形结构存储在数据库中(方案一、Adjacency List)的更多相关文章
- Java实现购物车功能:方式一:存放在session中.方式二:存储在数据库中
//将购物车产品加入到cookie中,方式同浏览记录.Java实现购物车,方式一(简易版):存储在session中.这种方式实现还不严谨,大家看的时候看思路即可.(1). JSP页面中,选择某一款产品 ...
- js上传文件带参数,并且,返回给前台文件路径,解析上传的xml文件,存储到数据库中
ajaxfileupload.js jQuery.extend({ createUploadIframe: function(id, uri) { //create frame var frameId ...
- 数据库:MySQL实战;左链接;查询WordPress数据库中的文章内容
在1年前,我用学生价租了一个阿里云服务器(是真的便宜啊),自己在CentOS系统上用命令行搭了个WordPress的环境,开始了为期一个月使用自建博客的历程. 事实证明,博客在类似博客园这样的平台上写 ...
- ASP.NET中让图片以二进制的形式存储在数据库中
今早有个网友问到我这问题,以前我都是直接在数据库中存文件名的,还没有试过存储整张图片到数据库中,上网搜索了一下,自己又测试了一番,代码如下:建立保存图片的表的SQL语句: USE [niunantes ...
- spring cloud config将配置存储在数据库中
Spring Cloud Config Server最常见是将配置文件放在本地或者远程Git仓库,放在本地是将将所有的配置文件统一写在Config Server工程目录下,如果需要修改配置,需要重启c ...
- 将文件存储到数据库中(MySQL)
package com.play; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundEx ...
- mysql的load data,高速将文本文件,插入数据库中
1语法 LOAD DATA [ LOW_PRIORITY | CONCURRENT ] [ LOCAL ] INFILE 'file_name.txt' [ REPLACE | IGNORE ] IN ...
- 存储过程: 存储过程(stored procedure)有时也称为sproc。存储过程存储于数据库中而不是在单独的文件中,有输入参数、输出参数以及返回值等。
存储过程示例一: 执行存储过程方法一: 执行存储过程方法二: 存储过程可以定义返回值: 修改存储过程: 利用存储过程查找三个表内的信息: 练习: 超市管理系统:表一:门店仓库表 MenDian ...
- Android端上传图片到后台,存储到数据库中 详细代码
首先点击头像弹出popwindow,点击相册,相机,调用手机自带的裁剪功能,然后异步任务类访问服务器,上传头像,保存到数据库中, 下面写出popwindow的代码 //设置popwindow publ ...
随机推荐
- MongoDB高级索引
1. 索引数组字段 创建和使用跟普通字段的索引一样. 2. 索引子文档字段: 创建索引: db.users.ensureIndex({"address.city":1," ...
- 不怕你配置不对,就怕你看的资料不对!MIM 与 SharePoint 同步完全配置指南。
为了更好的同步 User Profile,在 SharePoint 2010 中首次引入了 FIM (ForeFront Identity Manager) 用于编辑 User Profile 的同期 ...
- 记Javascript的编写方式的全新学习
前言 这次有幸参与前端的工作,对于前端开发学习了不少新知识,在此记录一下相比之前,完全不同的Javascript编写方式. 原来的编写方式 之前也是写过Javascript,就是常见的.js 文件写函 ...
- java线程池ThreadPool
package com.java.concurrent; import java.util.concurrent.ExecutorService; import java.util.concurren ...
- JS是按值传递还是按引用传递?【转载】
最近遇到个有趣的问题:“JS中的值是按值传递,还是按引用传递呢?” 在分析这个问题之前,我们需了解什么是按值传递(call by value),什么是按引用传递(call by reference). ...
- 单元测试框架 unittest 的运行方法if __name__ == '__main__': unittest.main()
1. if __name__ == '__main__': unittest.main()2. 测试用例实例根据测试的特点分组在一起. unittest为此提供了一个机制:测试套件由unittest' ...
- SQL Server 审计
审计(Audit)用于追踪和记录SQL Server实例或数据库中发生的事件,审计主要包括审计对象(Audit)和审计规范(Audit Specification),创建审计首先需要创建一个SQL S ...
- Hibernate框架学习之注解映射实体类
前面的相关文章中,我们已经介绍了使用XML配置文件映射实体类及其各种类型的属性的相关知识.然而不论是时代的潮流还是臃肿繁杂的配置代码告诉我们,注解配置才是更人性化的设计,于是学习了基本的映射 ...
- centos6.5安装rabbitmq3.6.14
The minimum version of Erlang/OTP required to run RabbitMQ server 3.6.0 through 3.6.14 is R16B03. St ...
- .Net开发小技巧
.NET项目开发中的小技巧 1.不要频繁的创建对象...这个损失是巨大的...new太多了,后果比较严重. 2.打开数据库后要及时的关闭连接,如果你不能做到一个open后跟一个close,那也没关系, ...