需求
昨天面试遇到的一个问题,要构建一个部门表,基础字段有部门名、部门id。
问,怎么设计这个部门?如果要你写一条SQL,根据部门ID查询出直接子部门和非直接子部门,那要怎么设计?多少个表?
解决方案
表结构设计
1 2 3 4 5 6
| CREATE TABLE dept ( dept_id INT AUTO_INCREMENT PRIMARY KEY, dept_name VARCHAR(50) NOT NULL, parent_id INT, ancestors VARCHAR(255) );
|
解释,ancestors 存放的是祖宗的主键值,主要是用来存放本部门的祖宗的。
1 2 3 4 5 6 7 8 9 10 11
| 假设部门的关系如下:
- A部门: ID=1 - B部门: ID=2(父部门是A) - C部门: ID=3(父部门是B)
在这种情况下,部门的`ancestors`字段会设置为:
- A部门的`ancestors`为空,因为它是顶级部门。 - B部门的`ancestors`为`1`,表示A是B的直接上级。 - C部门的`ancestors`为`1,2`,表示A是C的顶级上级,B是C的直接上级。
|
这样子做的好处是,查询直接子部门和非直接子部门只需要遍历这个ancestors 即可,无需借助其他的。如果没有ancestors
的帮助,我们需要在代码中通过parent_id逐层逐级的遍历列举以及合并列表。查询的sql也只需要这样子。
1 2 3 4 5
| select * from dept WHERE dept_id IN ( SELECT dept_id FROM dept WHERE find_in_set('查询的ID', ancestors ) )
# FIND_IN_SET('2', ancestors) 就是在 ancestors 字段中查找是否存在 '2', # 如果存在,返回其位置(非零值)。
|
缺点
每次维护表的时候,都要专门去维护ancestors 这个节点,会加大维护成本