比如用于描述这样一个人事管理关系:
需要如何设计数据库,并如何进行查询,才能迅速获得某一人的所有下属?
(效率为先,空间换时间的方式也是允许的,但务求速度,尽量优雅)
如果你只是想实现快速找到某个人的下属,可以这样实现
建立两个数据表,结构如下
表1 描述实际的树状关系
Id int, --当前记录Id
ParentId int, --上一级Id
Name nvarchar, --姓名
表2 描述相互间关系
Id int, 外键指向表1 的 Id
AncestorId int, --所有上级的Id
如关兴的记录 在表一中只有一条,即 ParentId 指向 关羽的记录
在表2中有两条记录 AncestorId 指向关羽的 和AncestorId指向刘备的。
查询所有下级只需要将该人的Id找到,并查找表2中 AncestorId =该人Id的记录,就是这个人
的所有下级。
先来说表结构,如果能够确定一共有多少个级别,那么可以为每一个级别建立一个表,不能确定的话,只能建立一个自引用的表 员工表(员工编号,上司编号,姓名,and so on)
所有下属?直系?还是都算上?直系的话最简单,无论是多表还是一个表,都可以使用 一个 inner join 来获取到
如果是所有下属,多表的情况下比较简单,多个inner join就可以了,惟一要解决的问题是如何知道你要查询的人是哪个级别,因为要用这个来确定where条件和开始inner join的表,所以需要给用户加一标识,而且一直在程序中判断着这个标识
所有下属,单表情况下,能够确定级别数量的话,和上面多表一样的处理方式即可,如果无法确定级别数,问题相当麻烦,因为没办法知道inner join多少次,我能想到的办法一次 inner join 3或5次,通过程序去判断,直到没有新数据被获取(存储过程实现比较好)
直系下属很好,所有下属的话,很是麻烦,尤其是级别数量不确定的时候,上面是最一般的做法,似乎都不太好,我再想想~~~~
一看到树我就想递归
我从来没考虑过关系型数据库怎么递归
自关联好像每次只能访问到父节点和子节点两层,不能展开到孙子和以下
同问了
如果可以确定树的层次很少且有限(例如组织结构)这种,可以在编码上做文章。例如:
刘备 是 101
关羽 是 101101
张飞 是 101102
关兴 是 101101101
关索 是 101101102
张苞 是 101102101
那么刘备的所有下属就是 编码 like '101%'
张飞的所有下属就是 编码 like '101102%'
不过这种方发要求实现假定每一层的人数上限。而且如果层次比较多则编码会嗷嗷长。
另一种方法是使用存储过程来实现。先建一个临时表。然后递归每一个层次,把数据插入临时表,然后返回这个临时表。可以使用动态构造SQL语句的方法把它作成通用的存储过程。
WITH EmpsCTE AS
(
SELECT EmployeeID, ReportsTo, FirstName, LastName
FROM dbo.Employees
WHERE EmployeeID = 2
UNION ALL
SELECT EMP.EmployeeID, EMP.ReportsTo, EMP.FirstName, EMP.LastName
FROM EmpsCTE AS MGR
JOIN dbo.Employees AS EMP
ON EMP.ReportsTo = MGR.EmployeeID
)
SELECT * FROM EmpsCTE;
这是我刚从书上看到的。希望对你有帮助,默认为100次递规,如果不限制的话可以SELECT * FROM EmpsCTE OPTION(MAXRECURSION 0)
这里只建立了一个表,另要建立覆盖索引,
CREATE UNIQUE INDEX idx_mgr_emp_ifname_ilname
ON dbo.Employees(ReportsTo, EmployeeID)
INCLUDE(FirstName, LastName);
你可以根据你的具体情况修改下.