[收集] 各式各样的 无限级分类 的数据库设计方案

黄平俊 发布于 2009/04/03 16:31
阅读 15K+
收藏 10

第一种方案:

表为两张,一张分类表,一张信息表。
表1:
`ID` int(10),
`cID` tinyint(3) ,
`title` varchar(255),
表2:
`cID` tinyint(3) ,
`parentID` tinyint(3), 
`order` tinyint(3) ,
`name` varchar(255),

这样可以根据cID = parentID来判断上一级内容,运用递归至最顶层 。

第二种方案:

设置parentID为varchar类型,将父类id都集中在这个字段里,用符号隔开,比如:1,3,6
这样可以比较容易得到各上级分类的ID,而且在查询分类下的信息的时候,可以使用如:Select * From information Where cID Like "1,3%"。不过在添加分类和转移分类的时候操作将非常麻烦。

以上两种方案地址:http://search.phpres.com/phpres-top2007,98552.html

第三种方案:

 每级分类递增两位数字,这样,每级分类的数目限定在100个之间,分类方法主要为编码法;
示例:
一级分类:01,02,03
二级分类:0101,0102,0103,0201,0202........
三级分类:010101,010102,010103,010104..........

数据库查询时使用 like '01%'就可得到一级分类01下的所有子分类,非常方便!
如果要列出所有分类的树型结构,只需用一条语句select * from pro_class order by code,再稍微处理一下就可。(其中,pro_class为产品分类表,code为类别编码)。


设计的数据库结构如下:

id:                    类别id,主键
classname:         类名
classcode:          类别编码
parent:             父id
left_child:          最左孩子id(或第一个孩子)
right_sibling:      右兄弟id
layer:                层级(第一级类别为1,第2级类别2,以此类推)

 

以上三种的缺点?优点?还有其它方案吗?

加载中
0
w
wuxudong

还有一个方案:

分类等价于一棵树, 每个节点增加两个属性: left, right.

然后按逆时针方向遍历整个树, 按遍历顺序给left,right赋值。 

对这样的一颗树, 所有 left < node.left & right > node.right 的就是node的 祖先节点

0
红薯
红薯

第三种方案并不能做无限级分类!!

第二种方案完全违反数据库设计范式

其实分类表一个就足以表达无限级的父子节点关系,就是通过增加一个父节点编号,但要便利一个树出来可能需要的查询太多了,解决的办法就是一次性把这张表全load出来,然后在程序里运算得到想要的树状结构。

纠结名字_我艹你妹
纠结名字_我艹你妹
一般人家的要求也是确定好的 3层 4层最多了,感觉第三种挺方便的 。
0
a
a394732530

我觉得第二种办法对“分类”二字来说是,是最现实,最合适的,我现在的项目就是用这种的。

首先它的特点是查询特别方便,处理稍麻烦,这正好符合“分类”的特点,我想按类别查询的次数怎么都比修改等处理的次数频繁吧?

例如各样各样的产品分类,为什么要分类?就是要按照分类来查询或其他处理,我不会一天有事没事就修改产品的类别吧?

楼上的说第二种方案完全违反数据库设计范式,我还真想向您请教????

还有你所提到的所谓解决办法,如果我没有理解错的话,应该是和我所说的特点相反,即查询用递归,特麻烦,修改添加等处理方便,如果是这样,那其中递归出来的效率低到什么程序你自己去体会一下吧

我觉得第二种办法对“分类”二字来说是,是最现实,最合适的

首先它的特点是查询特别方便,处理稍麻烦,这正好符合“分类”的特点,我想按类别查询的次数怎么都比修改等处理的次数频繁吧?

例如各样各样的产品分类,为什么要分类?就是要按照分类来查询或其他处理,我不会一天有事没事就修改产品的类别吧?

楼上的说第二种方案完全违反数据库设计范式,我还真想向您请教????

还有你所提到的所谓解决办法,如果我没有理解错的话,应该是和我所说的特点相反,即查询用递归,特麻烦,修改添加等处理方便,如果是这样,那其中递归出来的效率低到什么程序你自己去体会一下吧

j
jumplee
读取的时候会有缓存机制,即每一次修改的时候就把特定数组生成并缓存,所以效率没有问题。
0
tonyfox
tonyfox

神贴留名

我目前用的是第一种方案,我认为是最容易想到也是最简单的方案

0
烂菜

第三种适合分类深度不广,后台跑数据的时候使用,毕竟like效率比较低下

第一种可以融合成一张表是我比较喜欢的

0
s
sodarfish
第三种在节点的位置变化时你就悲剧了……………………
0
mark35
mark35

引用来自“wuxudong”的答案

还有一个方案:

分类等价于一棵树, 每个节点增加两个属性: left, right.

然后按逆时针方向遍历整个树, 按遍历顺序给left,right赋值。 

对这样的一颗树, 所有 left < node.left & right > node.right 的就是node的 祖先节点

这就是数据结构里面的“先序遍历”的算法,读取效率非常高,但对节点的更新开销大(需要同时更新相关节点左右值)
0
宏哥
宏哥
Oracle/Pg都支持connect by 进行树字节点递归查询.
0
中山野鬼
中山野鬼

没看懂什么意思?是不是一个信息表里的每个记录,希望能归类,而且分层的。用多次迭代算法不就解决了吗?每次迭代求出父节点的ID,如果ID为特定值则为根,也就是总分类。而每次迭代的输入是当前子分类。经过迭代,可以求出父类的信息。这种方式,计算强度只会和层级有关。N层的只要N次,非常快,也不存在遍历树的问题。

MSSQL做个从数据仓库,代分类数据全部集中进去。余下增加个字段作为上述映射数据存储。然后做个小的中间件,不是什么复杂的事情啊。表关联不是玩这个事情的。别把数据结构的东西折腾到数据库里。

在这点上我是同意 @红薯 的观点的。关于2不是个好方案。递归查询也不靠谱。必须要用到递归,只限于抽象的数据结构中,每个结点(每个表)之间没有同构性。有同构性,都可以直接线性方式解决,不能通过结点的地址关联方式遍历,会慢死的。

0
宏哥
宏哥

引用来自“中山野鬼”的答案

没看懂什么意思?是不是一个信息表里的每个记录,希望能归类,而且分层的。用多次迭代算法不就解决了吗?每次迭代求出父节点的ID,如果ID为特定值则为根,也就是总分类。而每次迭代的输入是当前子分类。经过迭代,可以求出父类的信息。这种方式,计算强度只会和层级有关。N层的只要N次,非常快,也不存在遍历树的问题。

MSSQL做个从数据仓库,代分类数据全部集中进去。余下增加个字段作为上述映射数据存储。然后做个小的中间件,不是什么复杂的事情啊。表关联不是玩这个事情的。别把数据结构的东西折腾到数据库里。

在这点上我是同意 @红薯 的观点的。关于2不是个好方案。递归查询也不靠谱。必须要用到递归,只限于抽象的数据结构中,每个结点(每个表)之间没有同构性。有同构性,都可以直接线性方式解决,不能通过结点的地址关联方式遍历,会慢死的。

select * from connectby('test','id','pid','id','0',0,';') as t(id int, pid int, level int, branch text, pos int)

PG一次查询就全部出来了


返回顶部
顶部