在一个系统设计中经常遇到分类数据表格设计,而且分类层数可能是不确定的。比方说一个商场的产品分类可以如下:
上图的数据结构就是一个树,数据表格设计有多种方法。每个分类可能在系统运行时需查询、增加、删除、修改、移动。不同的设计可能使各个功能点的性能不同,有些使查询快速和便利,有些新是增快速和便利,有些是删除、修改快和便利。针对上图可以有以下各种设计:
方案一:( 经常使用)
注 :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
缺点:较复杂的算法