mysql

无限级分类(或菜单)的高性能实现思路

SQL
2491
12
2016-07-25

一般说到无限级分类、菜单之类的东西,大家 (我) 的数据表设计一般是这样的

id parent_id title 更多字段...
1 0 衣物
2 1 上衣
3 1 裤子
4 3 西裤
5 4 长西裤
6 4 短西裤
7 2 衬衫

其中,parent_id表示父分类的id。由此可知,衣物分类下有上衣裤子两个二级分类;而裤子还有西裤这个三级分类……以此类推

这种设计比较常见 (就我所知),但缺点很明显。
例如需要显示下面这样的面包屑导航时:
衣物 > 裤子 > 西裤
就不得不进行多次循环

再例如,需要显示所有分类并表示层级时:

也不得不进行多次循环

那么,如何快速实现上述的常见功能呢?

实现

首先,示例表设计:

id title path level 更多字段...
1 衣物 0 0
2 上衣 0,1 1
3 裤子 0,1 1
4 西裤 0,1,3 2
5 长西裤 0,1,3,4 3
6 短西裤 0,1,3,4 3
7 衬衫 0,1,2 2

其中,path表示父级id列表。例如西裤0,1,3就表示衣物 > 裤子
实现面包屑时只要取出path字段的值,然后用,分割,得到id列表
再用where id in (1,3)即可

需要显示所有分类并表示层级时,使用下面的SQL:

SELECT *,concat(path,',',id) AS paths FROM menu ORDER BY paths

看到的结果是这样的:

id title path level paths
1 衣物 0 0 0,1
2 上衣 0,1 1 0,1,2
7 衬衫 0,1,2 2 0,1,2,7
3 裤子 0,1 1 0,1,3
4 西裤 0,1,3 2 0,1,3,4
5 长西裤 0,1,3,4 3 0,1,3,4,5
6 短西裤 0,1,3,4 3 0,1,3,4,6

那么,直接取出结果输出即可。level字段就是层级的意思
例如在PHP中,可以用str_repeat('--> ', $level)直接输出表示层级的前缀
并且连顺序都排好了,是不是很方便呢?

昵称
邮箱
网址
null的头像 2018-05-23 11:32

怎么让他们变成多维数据的形式

ac58cc3f3866e1620bfaa470c20f8088的头像 2018-01-19 21:52
ac58cc3f3866e1620bfaa470c20f8088

ac58cc3f3866e1620bfaa470c20f8088啊

axu的头像 2018-01-18 12:27
axu

有没有实际例子可以观摩?

mokeyjay的头像 2018-01-18 14:40
mokeyjay 博主

sql 语句都给出了还要啥例子?

auv的头像 2017-09-25 16:18
auv

请问这种结构要想实现一个父级分类迁移到另一个子级分类下,如何优化效率?

mokeyjay的头像 2017-09-25 16:27
mokeyjay 博主

以文中表格为例,假设要将西裤(ID:4)移动到衬衫(ID:7)下。首先 西裤level=衬衫level+1,用sql replace语句将path字段内的“0,1,3”替换为衬衫path+",7"(即0,1,2,7)即可

chloe的头像 2017-07-05 10:39
chloe

怎么排序呢,比如裤子要放在上衣前面的时候

mokeyjay的头像 2017-07-05 10:40
mokeyjay 博主

加权重字段,SQL语句order加多个条件

chloe的头像 2017-07-05 10:43
chloe

0,1,2和0,1,3后面加没有用的呀,

张晓东的头像 2016-08-09 20:01

这个方法真好用,赞一个,我之前还用递归的方法挨个比对 geili_org.gif

御坂网络的头像 2016-08-02 23:04

虽然我都知道,但是也要点个赞啊

mokeyjay的头像 2016-08-03 00:42
mokeyjay 博主

可以可以,6!