在一个系统设计中经常遇到分类数据表格设计,而且分类层数可能是不确定的。比方说一个商场的产品分类可以如下:

上图的数据结构就是一个树,数据表格设计有多种方法。每个分类可能在系统运行时需查询、增加、删除、修改、移动。不同的设计可能使各个功能点的性能不同,有些使查询快速和便利,有些新是增快速和便利,有些是删除、修改快和便利。针对上图可以有以下各种设计:

 

 

方案一:( 经常使用)

:Id:类型的唯一标识符;name:类型名称;parentId:父类ID(参照本表id)
查询 :单一查询方便;但查询某分类的全部子类就不方便(需迭代查询 ),不同的数据库有不同的语句,有些数据库还不支持迭代查询。

新增、修改、删除 :新增、修改、删除比较便利(删除某分类时可能得逐级向上删除或者设置CASCADE

 

方案二:

 

注: Id:类型的唯一标识符;name:类型名称;code:类型编码

查询 :单一查询方便,查询某分类的全部子类也方便(使用 like) 。
修改 、删除:修改、删除比较便利
新增 :新增还需查询其父类code,然后再加上此类#id(不很便利)

致命缺点 :code长度有限,只支持层数有限的树形结构,树形不大时可以使用此结构

 

方案三:(综合方案二方案一)

 

此方案综合了方案一、二,弥补了方案一的一些缺点但也带进了方案而的缺点

 

最想说的是方案四
先看看下面这个数据结构:

 

表结构:

Left:左支标识 Right:右支标识

这个数据结构的查询需要一定的算法来支持,
查询:单一查询方便

查询分类根节点:

Select * from kind_table where left=1;

查询分类(left=pleft, right=pright)所以子类(此处不需迭代查询):

Select * from kind_table where left> pleft and right<pright;

修改:
修改一个分类(得连带修改其所有子类),只需遵循一条原则:

where left> pleft and right<pright;

新增:

新增一个分类(其父类为id=pid,left=pleft, right=pright)

Update kind_table set right  = right+ 2  where  right >= pright;
Update kind_table set left  =left+2     where  left > pright;
Insert into  kind_table values($id,$name,pid, pright, pright+1);

删除:
删除一个分类(id=cid,left=cleft, right=cright)

Delete from kind_table where left>= pleft and right=<pright;
Update kind_table set right  = right-( cright- cleft+1)  where  right > cright;
Update kind_table set left  =left-( cright- cleft+1)     where  left > cleft;

一些特殊查询:

查询一个父类 (id=pid,left= pleft, right=pright)的所有子类的个数:---不需查询数据库
所有子类的个数:(Pright- pleft-1)/2

判断一个节点是否为叶子节点 :(Pright- pleft-1)/2 ==0 或者Pright- pleft==1

缺点:较复杂的算法