预排序树实现无限极分类

一.概念

  • 左右值无限级分类,也称为预排序树无限级分类
  • 是一种有序的树状结构
  • 于这些树状结构中的每一个节点都有一个 左值右值

二.规则

  • 每一个 后代节点左值 > 父节点左值
  • 每一个 后代节点右值 < 父节点右值
  • 每一个节点的 右值 < 左值
    Paste_Image.png

三.新增节点

  • 新增顶级分类:
    • 获取该树中 最大右值;
    • 左值 = 最大右值 + 1;
    • 右值 = 最大右值 + 2;
  • 新增子节点
    • 首先获取 父节点右值
    UPDATE `catagory` SET `lft` = `lft`+2 WHERE `lft`>`父节点右值`
    UPDATE `catagory` SET `rgt` = `rgt` + 2 WHERE `rgt`>= `父节点右值`
    
    • 新增节点左值 = 父节点右值
    • 新增节点右值 = 新增节点左值 + 1

四. 删除节点

  • 获取删除节点的左右值 $lft, $rgt
  • 删除该节点以及所有后代节点
DELETE FROM `catagory` WHERE `lft`>=$lft AND `rgt`<=$Rgt"
  • 更新左右值
$Value=$rgt-$lft+1;
UPDATE `catagory` SET `lft`=`lft`- $Value WHERE `lft`>$lft
UPDATE `catagory` SET `rgt`=`rgt`- $Value WHERE `rgt`>$rgt"

五.数据准备

CREATE TABLE `nested_category` (
  `category_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
  `name` varchar(18) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',
  `lft` int(4) NOT NULL,
  `rgt` int(4) NOT NULL,
  KEY `category_id` (`category_id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

INSERT INTO `nested_category` VALUES 
(1,'商品',1,26),
(2,'化妆品',2,7),
(3,'食品',8,9),
(4,'酒',10,15),
(5,'服装',16,17),
(6,'家电',18,23),
(7,'鞋帽',24,25),
(8,'面霜',3,4),
(9,'面膜',5,6),
(10,'白酒',11,12),
(11,'红酒',13,14),
(12,'冰箱',19,20),
(13,'空调',21,22);

数据查看
mysql> select * from nested_category;
+-------------+-----------+-----+-----+
| category_id | name      | lft | rgt |
+-------------+-----------+-----+-----+
|           1 | 商品    |   1 |  26 |
|           2 | 化妆品 |   2 |   7 |
|           3 | 食品    |   8 |   9 |
|           4 | 酒       |  10 |  15 |
|           5 | 服装    |  16 |  17 |
|           6 | 家电    |  18 |  23 |
|           7 | 鞋帽    |  24 |  25 |
|           8 | 面霜    |   3 |   4 |
|           9 | 面膜    |   5 |   6 |
|          10 | 白酒    |  11 |  12 |
|          11 | 红酒    |  13 |  14 |
|          12 | 冰箱    |  19 |  20 |
|          13 | 空调    |  21 |  22 |
+-------------+-----------+-----+-----+

六. 获取所有后代节点

select * from nested_category where lft > 18 and rgt < 23;
+-------------+--------+-----+-----+
| category_id | name   | lft | rgt |
+-------------+--------+-----+-----+
|          12 | 冰箱 |  19 |  20 |
|          13 | 空调 |  21 |  22 |
+-------------+--------+-----+-----+
2 rows in set (0.00 sec)

七.计算后代数量

  • 后代的数量 = (右值 - 左值 - 1) / 2。减少1的原因是排除该节点本身

八. 判断叶子节点

  • 右值 - 左值 = 1
  • 获取叶子节点
mysql> select * from nested_category  where rgt - lft = 1;
+-------------+--------+-----+-----+
| category_id | name   | lft | rgt |
+-------------+--------+-----+-----+
|           3 | 食品   |   8 |   9 |
|           5 | 服装   |  16 |  17 |
|           7 | 鞋帽   |  24 |  25 |
|           8 | 面霜   |   3 |   4 |
|           9 | 面膜   |   5 |   6 |
|          10 | 白酒   |  11 |  12 |
|          11 | 红酒   |  13 |  14 |
|          12 | 冰箱   |  19 |  20 |
|          13 | 空调   |  21 |  22 |
+-------------+--------+-----+-----+

九. 检索单一路径

select 
    parent.name,
    parent.category_id, 
    parent.lft,
    parent.rgt
from 
    nested_category as node, nested_category as parent 
where 
    node.lft between parent.lft and parent.rgt and node.name = '空调' 
    order by parent.lft;

+--------+-------------+-----+-----+
| name   | category_id | lft | rgt |
+--------+-------------+-----+-----+
| 商品 |           1 |   1 |  26 |
| 家电 |           6 |  18 |  23 |
| 空调 |          13 |  21 |  22 |
+--------+-------------+-----+-----+
3 rows in set (0.00 sec)

十. 检索分类深度

select 
    node.name as name,  (count(parent.name) - 1) as deep
from 
    nested_category as node,
    nested_category as parent
where node.lft between parent.lft and parent.rgt
group by node.name
order by node.lft
+-----------+------+
| name      | deep |
+-----------+------+
| 商品    |    0 |
| 化妆品 |    1 |
| 面霜    |    2 |
| 面膜    |    2 |
| 食品    |    1 |
| 酒       |    1 |
| 白酒    |    2 |
| 红酒    |    2 |
| 服装    |    1 |
| 家电    |    1 |
| 冰箱    |    2 |
| 空调    |    2 |
| 鞋帽    |    1 |
+-----------+------+
13 rows in set (0.03 sec)

十一. 检索某个节点的子节点(不包含后代节点)

select * from (
    select 
        node.name as name,  
        (count(parent.name) - 1) as deep 
    from 
        nested_category as node,
        nested_category as parent 
    where node.lft between parent.lft and parent.rgt 
    group by node.name 
    order by node.lft
) as a where a.deep <= 1; 
+-----------+------+
| name      | deep |
+-----------+------+
| 商品    |    0 |
| 化妆品 |    1 |
| 食品    |    1 |
| 酒       |    1 |
| 服装    |    1 |
| 家电    |    1 |
| 鞋帽    |    1 |
+-----------+------+
7 rows in set (0.00 sec)

十二.总结

  • 我们看到上边的获取深度检索某个节点的子节点实现上用到了子查询,sql语句很复杂.
  • 所以我的解决办法是在数据结构上增加 深度父id 两个字段
  • 因为分类是前台页面操作人员操作的, 也就是说操作的时候就知道深度, 每次新增时候将 深度父id 带上就可以方便的解决复杂sql语句的问题;

参考文章: http://blog.csdn.net/i_bruce/article/details/41558063

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容