对于组织架构中的员工层次关系我们应该怎么建模呢?
如下图所示:
此类结构通常有两个主要特点:
1、一个孩子有且只有一个父亲
2、树的深度不确定
为了解决这种结构,我们一般会建一张下面的表:
方案一(Adjacency List)
CREATE TABLE Employees(
employee_id int,
employee_name varchar2(100),
parent_id int
);
每个员工在Employees表中会有一条记录,并通过parent_id来记录其直属领导的employee_id,这样做很简单明了,但是却存在一些弊端。
考虑如下问题:
1、如何得到某个员工的直属领导?
2、如何得到某个领导的直属下属?
3、如何得到某个领导全部下属(下属的下属)?
问题1、2都很简单,一次自连接就解决了:
1、
2、
但问题3呢?
两种人会有两种做法,一种觉得可以在程序里做,把问题2的SQL循环执行最终把结果拼起来就OK了;
一种是觉得我可以使用多次自连接,比如我知道这下领导最多有两级下属,我就可以这样做:
select child.employee_id,child.employee_name,child1.employee_id,child1.employee_name
from employees self inner join employees child on child.parent_id=self.employee_id
left join employees child1 on child1.parent_id=child.employee_id and
where self.employee_id=1010
上面两种方法看似都可以解决问题,但是别忘了此类树结构的一个很重要的特点,那就是深度的不确定性(就算确定,如果层次很深,20级),
性能及可扩展性将是一个很大的问题。
那怎么办呢?一时间好像看起来别无他法啊。
好消息是使用Oracle 10g及以上或者SQL Server 2005及以上的朋友可以直接使用数据库特有的SQL特性来解决这个问题了。
例如在Oracle中可以使用层次查询
那使用MySQL或者其不支持层次查询的数据库怎么办呢?难道只能用前面两种笨方法?
答案是否定的,你需要重新设计你的表模型。
How to design?
方案二(Path Enumeration)
CREATE TABLE Employees_Path(
employee_id int,
employee_name varchar2(100),
path varchar2(1000)
);
此种方案借助了unix文件目录的思想,如下图所示:
我们需要做的就是正确的维护这个PATH值,现在如果我们要查询任意领导(比如Michele)的所有下属就只需要这样即可:
同样的,如果我们需要查询任意员工(比如Chris)的所有领导也只需要这样即可:
缺点:
1、PATH值由程序来维护,无法在数据库一级确保数据的有效性
2、当树的层级太深有可能会超过PATH字段的长度,所以其能支持的最大深度并非无限的。
方案三(Nested Sets)
CREATE TABLE EMPLOYEES_NESTEDSETS(
EMPLOYEE_ID INT,
EMPLOYEE_NAME VARCHAR2(100),
NSLEFT INT,
NSRIGHT INT
);
该方案采用深度优先遍历给树中的每个节点分配两个值,分别存在NSLEFT和NSRIGHT中。如下图所示
每个节点左边的的值存放在NSLEFT中,右边的值存放在NSRIGHT中;节点左边的值比该节点的所有子孙节点值都要小,节点右边的值比该节点的所有子孙节点值都要大。
例如Hell Mayes左边的值为2,其比Hell Mayes的所有子孙节点的值都要小(3,4,5,10,6,7,8,9)
Hell Mayes右边的值为11,其比Hell Mayes的所有子孙节点的值都要大(3,4,5,10,6,7,8,9)
有了这个规则之后,如果想要查找某个节点的子孙或都祖先就非常容易了。
回到我们前面的题目中来,假设我要查找Helen Mayes的所有下属员工,我们可以这样:
那如果我们要查找Helen Mayes的所有领导呢?
Nested Sets这种方案还有一个优点就是,当你删除了一个非叶子节点的时候,该节点的所有子孙节点会自动成为该节点父节点的子孙,并同样满足前面所说的条件。
缺点:
在Adjacency List方案中很好回答的问题,在Nested Sets中却变得困难起来
比如我想要查找任意领导(比如Helen Mayes)的直属下属,在Nested Sets中你需要这样做
怎么样,够复杂吧? 其逻辑就是 首先找到Helen Mayes的所有下属,然后在去查找这些下属没有属于Helen Mayes下属的上级.........WTF...........
另外,移动和新增加节点也比较复杂
比如我们要在Helen Mayes和Chris Jones之间插入一名员工Scott,如下图所示
从上图基本上就可以看出来我们要更改的地方了......需要重新生成比新插入节点的nsleft值大的所有节点的nsleft和nsright值
非常复杂......
方案四(Closure Table)
CREATE TABLE Employees(
employee_id int,
employee_name varchar2(100)
);
CREATE TABLE TreePaths (
ancestor_key int,
member_key int,
Distance int,
is_leaf int
);
Closure Table将树中每个节点与其子孙节点的关系都存储了下来,如下图所示:
注意:每个节点都有一条到其本身的记录,如上表的第一条、第四条、第六条记录
Distance是祖先节点到其本身之间的深度
IS_LEAF用于标识该节点是否为叶子节点
有了这张关系表之后,下面让我们用具体例子来感受其带来的好处
查找某个领导(Helen Mayes)的所有下属员工信息
select * from Employees a, TreePaths b where a.employee_id = b.ancestor_key and a.employee_name = 'Helen Mayes' and b.distance<>0
查找某个领导(Helen Mayes)的所有直属员工信息
select * from Employees a, TreePaths b where a.employee_id = b.ancestor_key and a.employee_name = 'Helen Mayes' and b.distance=1
查找某个员工的所有领导
select * from Employees a, TreePaths b where a.employee_id = b.member_key and a.employee_name = 'Helen Mayes' and b.distance<>0
由于时间的关系(现在已经凌晨1点),其它的关于增删改查的方法请大家自行验证。
相关推荐
BIEE BIEE BIEE BIEE BIEE BIEE BIEE
biee 仪表盘参数接收参数接收方法。形象易于学习,里面含有实例。
本文内容主要介绍如何在BI项目中应用父子层级结构,有两种可选的应用方案并提供了对父子层级结构应用后的数据权限控制策略。 在进入正题前先介绍一些基本内容。
BIEE入门视频,BIEE 资料,轻松学会BIEE,BIEE教程
BIEE_仪表盘传参数接收方法 比较好的文档
BIEE的资料库(Repository)是一个后缀名为rpd的物理文件,其中存储了三类元数据:数据源物理模型,逻辑模型,以及展现模型。Oracle BI Server是资料库的使用者:在前端,BI Server通过ODBC将资料库中的逻辑模型及...
BI总结-BIEE11G-RPD过滤用户权限,BI总结-BIEE11G-RPD建模
主要介绍了BIEE如何创建三层结构,以及一个简单的demo
BIEE配置ODBC连接impala BIEE配置ODBC连接impala BIEE配置ODBC连接impala
oracle biee开发中遇到的变量使用方法
通过java调用oracle的biee接口webservice,主要实现三种方式: 1.通过路径获取图片和表格数据xml。 2.通过biee的逻辑sql获取图片和表格数据xml。 3.获取biee下的所有路径。 需要jar主要为axis.jar wsdl4j-1.5.1.jar ...
Oracle BIEE 架构介绍PPT, 对BIEE架构的介绍很清楚,适合想了解BIEE的人群。
BIEE树状菜单-根据用户动态显示有权限看到的节点
biee10g的一个小案例 帮助biee初学者可以很快全面了解biee
biee的一个很重要的功能——回写 biee的一个很重要的功能——回写
一篇BIEE的PDF,一篇BIEE的PDF一篇BIEE的PDF一篇BIEE的PDF一篇BIEE的PDF
BIEE administrator tool使用
biee提供webservice接口java调用里面的方法实现跟java程序结合
Oracle BIEE(简称BIEE)作为Oracle的新的商业智能平台企业版,起源于Oracle所收购的Siebel公司,BIEE原来叫做Siebel Analytic。
oracle BIEE技术手册 oracle BIEE技术手册 oracle BIEE技术手册