MySQL閉包表

測試數據來自於博客: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

操作起來的確是很方便。爲了在表中存儲樹,其實還有別的做法,比如路徑枚舉(知道用這樣的設計,但是不知道叫這個名字)這是在項目中用到的。

這裏推薦一篇博客,很好的解釋了這兩種的區別:https://www.cnblogs.com/boboxing/p/7055251.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章