2024年4月12日发(作者:)

采用左右值编码来存储无限分级树形结构的数据库表设计

之前我介绍过一种按位数编码保存树形结构数据的表设计方法,详情见:浅谈数据库设计技巧(上)

该设计方案的优点是:只用一条查询语句即可得到某个根节点及其所有子孙节点的先序遍历。由于消除了递归,在数据记录量较

大时,可以大大提高列表效率。但是,这种编码方案由于层信息位数的限制,限制了每层能所允许的最大子节点数量及最大层数。同时,

在添加新节点的时候必须先计算新节点的位置是否超过最大限制。

上面的设计方案必须预先设定类别树的最大层数以及最大子节点数,不是无限分级,在某些场合并不能采用,那么还有更完美的

解决方案吗?通过 google的搜索,我又探索到一种全新的无递归查询,无限分级的编码方案——左右值。原文的程序代码是用php写

的,但是通过仔细阅读其数据库表设计说明及相关的sql语句,我彻底弄懂了这种巧妙的设计思路,并在这种设计中新增了删除节点,

同层平移的需求(原文只提供了列表及插入子节点的sql语句)。

下面我力图用比较简短的文字,少量图表,及相关核心sql语句来描述这种设计方案:

首先,我们弄一棵树作为例子:

商品

|---食品

| |---肉类

| | |--猪肉

| |---蔬菜类

| |--白菜

|---电器

|--电视机

|--电冰箱

采用左右值编码的保存该树的数据记录如下(设表名为tree):

Type_id

1

2

3

4

5

6

7

8

9

Name

商品

食品

肉类

猪肉

蔬菜类

白菜

电器

电视机

电冰箱

Lft

1

2

3

4

7

8

12

13

15

Rgt

18

11

6

5

10

9

17

14

16

第一次看见上面的数据记录,相信大部分人都不清楚左值(Lft)和右值(Rgt)是根据什么规则计算

出来的,而且,这种表设计似乎没有保存父节点的信息。下面把左右值和树结合起来,请看:

1商品18

+---------------------------------------+

2食品11 12电器17

+-----------------+ +---------------------+

3肉类6 7蔬菜类10 13电视机14 15电冰箱16

4猪肉5 8白菜9

请用手指指着上图中的数字,从1数到18,学习过数据结构的朋友肯定会发现什么吧?对,你手指

移动的顺序就是对这棵树的进行先序遍历的顺序。接下来,让我讲述一下如何利用节点的左右值,得到该

节点的父节点,子孙节点数量,及自己在树中的层数。

假定我们要对节点“食品”及其子孙节点进行先序遍历的列表,只需使用如下一条sql语句:

select * from tree where Lft between 2 and 11 order by Lft asc

查询结果如下:

Type_id

2

3

4

5

6

那么某个节点到底有多少子孙节点呢?很简单,子孙总数 =(右值-左值-1)/2

以节点“食品”举例,其子孙总数=(11-2-1)/ 2 = 4

同时,我们在列表显示整个类别树的时候,为了方便用户直观的看到树的层次,一般会根据节点所处

的层数来进行相应的缩进,那么,如何计算节点在树中的层数呢?还是只需通过左右值的查询即可,以节

点“食品”举例,sql语句如下:

Name

食品

肉类

猪肉

蔬菜类

白菜

Lft

2

3

4

7

8

Rgt

11

6

5

10

9