欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MySQL闭包表

程序员文章站 2022-03-19 15:00:46
...

测试数据来自于博客:https://www.cnblogs.com/linjiqin/p/9523033.html

闭包表是为了解决在数据库中存储树形数据而引出的解决方案。通常闭包表会有两个表,一个记录节点信息,一个记录关系。

举例如下:

# 示例树
# root(0)
#   |
#   |____a(1)
#   |    |____a1(2)
#   |    |____a2(3)
#   |
#   |____b(4)
#        |____b1(5)
#        |____b2(6)
#        |____c(7)
#             |____c1(8)
#             |____d(9)
#                  |____e(10)
create table node
(
    id   int         not null primary key,
    name varchar(50) null
)

create table node_relation
(
    ancestor   int     not null comment '祖先节点',
    descendant int     not null comment '子孙节点',
    distance   tinyint null comment 'distance, 也就是从祖先到子孙节点的距离',
    constraint unique_index
        unique (ancestor, descendant)
)

INSERT INTO node (id, name) VALUES (0, 'root');
INSERT INTO node (id, name) VALUES (1, 'a');
INSERT INTO node (id, name) VALUES (2, 'a1');
INSERT INTO node (id, name) VALUES (3, 'a2');
INSERT INTO node (id, name) VALUES (4, 'b');
INSERT INTO node (id, name) VALUES (5, 'b1');
INSERT INTO node (id, name) VALUES (6, 'b2');
INSERT INTO node (id, name) VALUES (7, 'c');
INSERT INTO node (id, name) VALUES (8, 'c1');
INSERT INTO node (id, name) VALUES (9, 'd');
INSERT INTO node (id, name) VALUES (10, 'e');

INSERT INTO node_relation (ancestor, descendant, distance) VALUES (0, 1, 1);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (0, 2, 2);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (0, 3, 2);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (0, 4, 1);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (0, 5, 2);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (0, 6, 2);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (0, 7, 2);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (0, 8, 3);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (0, 9, 3);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (0, 10, 4);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (1, 1, 0);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (1, 2, 1);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (1, 3, 1);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (2, 2, 0);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (3, 3, 0);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (4, 4, 0);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (4, 5, 1);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (4, 6, 1);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (4, 7, 1);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (4, 8, 2);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (4, 9, 2);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (4, 10, 3);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (5, 5, 0);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (6, 6, 0);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (7, 7, 0);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (7, 8, 1);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (7, 9, 1);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (7, 10, 2);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (8, 8, 0);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (9, 9, 0);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (9, 10, 1);
INSERT INTO node_relation (ancestor, descendant, distance) VALUES (10, 10, 0);

1,如果想要获取某个节点以及节点下的所有节点信息:

select a.id, a.name
from node a
         join node_relation b on a.id = b.descendant
where b.ancestor = 4;

输出:
id      name
4	b
5	b1
6	b2
7	c
8	c1
9	d
10	e 

2,获取所有的内部节点,也就是非叶子节点:

select distinctrow b.ancestor as id, a.name
from node_relation b
         right join node a on a.id = b.ancestor
where distance != 0;
输出:
id      name
0	root
1	a
4	b
7	c
9	d

3,查询所有叶子节点:

select *
from node
where id not in (select distinct ancestor from node_relation where distance != 0);
输出:
id    name
2	a1
3	a2
5	b1
6	b2
8	c1
10	e

4,整个树的结构为:

select *
from node_relation
where distance = 1;
输出:
ancestor descendant distance
0	1	1
0	4	1
1	2	1
1	3	1
4	5	1
4	6	1
4	7	1
7	8	1
7	9	1
9	10	1

操作起来的确是很方便。为了在表中存储树,其实还有别的做法,比如路径枚举(知道用这样的设计,但是不知道叫这个名字)这是在项目中用到的。

MySQL闭包表

这里推荐一篇博客,很好的解释了这两种的区别:https://www.cnblogs.com/boboxing/p/7055251.html

相关标签: 个人