以空间换时间的经典方案,闭包表 Closure Table
下面是要存储的结构图:
[[../../Attachments/c6eb1f0aeba7520e3125de4cfbfdc407_MD5.png|![|500]]
需要回答的问题依旧是这样几个:
1.查询小天的直接上司。
2.查询老宋管理下的直属员工。
3.查询小天的所有上司。
4.查询老王管理的所有员工。
方案三、Closure Table 闭包表法,保存每个节点与其各个子节点的关系,也就是记录以其为根节点的全部子节点信息。直接上代码就明白了:
这里要创建两个表,一个表用来存储信息:
CREATE TABLE employees3(
eid INT,
ename VARCHAR(100),
position VARCHAR(100)
)
一个表用来存储关系:
CREATE TABLE emp\_relations(
root\_id INT,
depth INT,
is\_leaf TINYINT(1),
node\_id INT
)
这里的 root_id 用来存放以其为根节点的路径,node_id 表示节点处的 eid,depth 表示根节点到该节点的深度,is_leaf 表示该节点是否为叶子节点。
接下来插入数据:
[[../../Attachments/53a21fe7c6b384bcdf9638ddd11fde6c_MD5.png|![|500]]
[[../../Attachments/88217460bc270007e9d9862c6434652d_MD5.png|![|475]]
[[../../Attachments/3f9c4aea4350e1dd1a11a83d8ba73651_MD5.png|![|500]]
可以看出,这个关系表有点大,我们先来看看查询效果如何:
1.查询小天的直接上司。
这里只需要在关系表中找到 node_id 为小天 id,depth 为 1 的根节点 id 即可。
SELECT e2.ename BOSS FROM employees3 e1,employees3 e2,emp\_relations rel
WHERE e1.ename='小天' AND rel.node\_id=e1.eid AND rel.depth=1 AND e2.eid=rel.root\_id
查询结果如下:
[[../../Attachments/e7f43082a28abcd78222d5b36d8cf096_MD5.png|![|500]]
2.查询老宋管理下的直属员工。
思路差不多,只要查询 root_id 为老宋 eid 且深度为 1 的 node_id 即为其直接下属员工 id
SELECT e1.eid,e1.ename 直接下属 FROM employees3 e1,employees3 e2,emp\_relations rel
WHERE e2.ename='老宋' AND rel.root\_id=e2.eid AND rel.depth=1 AND e1.eid=rel.node\_id
查询结果如下:
[[../../Attachments/a364121bf08f33afd5ab59c8f7914f24_MD5.png|![|500]]
3.查询小天的所有上司。
只要在关系表中找到 node_id 为小天 eid 且 depth 大于 0 的 root_id 即可
SELECT e2.eid,e2.ename 上司 FROM employees3 e1,employees3 e2,emp\_relations rel
WHERE e1.ename='小天' AND rel.node\_id=e1.eid AND rel.depth>0 AND e2.eid=rel.root\_id
查询结果如下:
[[../../Attachments/05dcd97fe39ba5f614cb4907dd849d0c_MD5.png|![|500]]
4.查询老王管理的所有员工。
只要在关系表中查找 root_id 为老王 eid,depth 大于 0 的 node_id 即可
SELECT e1.eid,e1.ename 下属 FROM employees3 e1,employees3 e2,emp\_relations rel
WHERE e2.ename='老王' AND rel.root\_id=e2.eid AND rel.depth>0 AND e1.eid=rel.node\_id
查询结果如下:
[[../../Attachments/a5138cba584bc2304f8d30360c6773e0_MD5.png|![|500]]
我们可以发现,这四个查询的复杂程度是一样的,这就是这种存储方式的优点,而且可以让另一张表只存储跟节点紧密相关的信息,看起来更简洁。但缺点也显而易见,关系表会很庞大,当层次很深,结构很庞大的时候,关系表数据的增长会越来越快,相当于用空间效率来换取了查找上的时间效率。
优缺点:Closure Table
优点:在查询树形结构的任意关系时都很方便。
缺点:需要存储的数据量比较多,索引表需要的空间比较大,增加和删除节点相对麻烦。
适用场合:纵向结构不是很深,增删操作不频繁的场景比较适用。