原理说明可以看这个帖子:

http://jakezzz.blog.sohu.com/53099673.html

把代码整理一下,试了一下,比较好使,根据实际需要改改就基本OK。

(1)建表

DROP TABLE IF EXISTS `pcms_channel`;

CREATE TABLE IF NOT EXISTS `pcms_channel` (

`cid` tinyint(3) unsigned NOT NULL auto_increment,

`name` char(10) NOT NULL COMMENT '频道名称',

`parentid` tinyint(4) NOT NULL COMMENT '父级ID',

`lft` tinyint(4) NOT NULL COMMENT '左值',

`rgt` tinyint(4) NOT NULL COMMENT '右值',

`lv` tinyint(3) unsigned NOT NULL default '0' COMMENT '级层',

`themeid` tinyint(3) unsigned NOT NULL default '1' COMMENT '使用的主题的ID',

PRIMARY KEY  (`cid`),

KEY `parentid` (`parentid`,`lft`,`rgt`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;

(2)导入测试数据

INSERT INTO `pcms_channel` (`cid`, `name`, `parentid`, `lft`, `rgt`, `lv`, `themeid`) VALUES

(1, 'phpoocms', 0, 1, 12, 0, 1),

(2, 'test', 1, 2, 7, 1, 1),

(3, 'te', 2, 3, 6, 2, 1),

(4, 'tes', 1, 8, 9, 1, 1),

(5, 'dd', 3, 4, 5, 3, 1),

(6, 'fromphp', 1, 10, 11, 1, 1);

(3)添加节点的存储过程

调用方法:call addChannel (1,"aaaa")

返回1000才是成功,其它是失败了。

DROP Procedure `addChannel` ;

DELIMITER |

/*

* pid,添加到的目标节点ID

* name,节点名称

*/

CREATE PROCEDURE `addChannel`(in pid int,in name varchar(20))

BEGIN

DECLARE pr INT;/*右值*/

DECLARE lvv INT;/*层级*/

DECLARE aff INT; /* SQL 影响记录条数 */

DECLARE af INT DEFAULT 0; /* 总影响记录条数*/

SET @result = null;

/* 目标节点的右值,Level值 */

SELECT `rgt`,`lv` INTO pr,lvv FROM `pcms_channel` WHERE `cid` = pid;

IF pr THEN

START TRANSACTION;

/* 更新右侧节点的left值 */

UPDATE `pcms_channel` SET `lft`=`lft`+2 WHERE `lft`>pr;

SELECT ROW_COUNT() INTO aff;

SET af = aff+af;

/* 更新右侧节点的right值 */

UPDATE `pcms_channel` SET `rgt`=`rgt`+2 WHERE `rgt`>=pr;

SELECT ROW_COUNT() INTO aff;

SET af = aff+af;

/* 增加节点自己 */

INSERT INTO `pcms_channel` (`name`,`parentid`,`lft`,`rgt`,`lv`) VALUES (name,pid,pr,pr+1,lvv+1);

SELECT ROW_COUNT() INTO aff;

SET af = aff+af;

IF af >= 2 THEN

COMMIT;

SET @result = 1000;

SELECT 1000 AS result;

ELSE

ROLLBACK;

SET @result = 1002;

SELECT 1002 AS result;

END IF;

ELSE

SET @result = 1001;

SELECT 1001 AS result;

END IF;

END |

(4)删除节点(只能删除叶节点,有子节点的不允许删除)

调用方法:call delChannel (5)

DROP Procedure `delChannel` ;

DELIMITER |

/*

* pid,要删除的节点ID

* 节点有子节点时,不允许删除,

* 所以问题简单了,只删除自己就可以了,不需要删除所有子节点。

*/

CREATE PROCEDURE `delChannel`(in pid int)

BEGIN

DECLARE pl INT; /* 左节点ID */

DECLARE pn INT; /* 子节点数量 */

DECLARE aff INT; /* SQL 影响记录条数 */

DECLARE af INT DEFAULT 0; /* 总影响记录条数*/

SET @result = null;

SET @parentid = null;

SET @name = null;

/* 查询要删除的节点,及它的子节点 ,得到左节点ID,子节点数量,父节点ID和节点名称是给移动节点使用的。 */

SELECT a.`lft`,IFNULL(COUNT(b.`cid`),0),a.`parentid`,a.`name`

INTO pl,pn,@parentid,@name

FROM `pcms_channel` AS a LEFT JOIN `pcms_channel` AS b

ON a.`cid`=b.`parentid`

WHERE a.`cid`=pid

GROUP BY b.`parentid`;

/* 如果子节点数量为0 */

IF pl&&!pn THEN

IF pl!=1 THEN /* 左节点是1的认为是根节点,不让删除*/

START TRANSACTION;

/* 更新右侧节点的left值 */

UPDATE `pcms_channel` SET `lft`=`lft`-2 WHERE `lft`>pl;

SELECT ROW_COUNT() INTO aff;

SET af = aff+af;

/* 更新右侧节点的right值 */

UPDATE `pcms_channel` SET `rgt`=`rgt`-2 WHERE `rgt`>pl;

SELECT ROW_COUNT() INTO aff;

SET af = aff+af;

/* 删除节点自己 */

DELETE FROM `pcms_channel` WHERE `cid` = pid;

SELECT ROW_COUNT() INTO aff;

SET af = aff+af;

IF af >= 2 THEN

COMMIT;

SET @result = 1000;

SELECT 1000 AS result;

ELSE

ROLLBACK;

SET @result = 1002;

SELECT 1002 AS result;

END IF;

ELSE

SET @result = 1004;

SELECT 1004 AS result;

END IF;

ELSEIF pn&&pl THEN /* 子节点数量>0则报错 */

SET @result = 1003;

SELECT 1003 AS result;

ELSE

SET @result = 1001;

SELECT 1001 AS result;

END IF;

END |

(5)移动节点(只能移动叶节点,是通过先删除,再添加的办法实现的。)

调用方法:call moveChannel (5,4)

DROP Procedure `moveChannel` ;

DELIMITER |

/*

* pid,移动的节点ID

* tid,目标节点ID

*/

CREATE PROCEDURE `moveChannel`(pid int,tid int)

BEGIN

/* 节点ID是为1的是根节点,不让移动(这么判断不对吧?左节点是1的不让删除吧) */

IF pid=1 THEN

SELECT 1004 AS result;

ELSE

/* 不能移动到自己 */

IF pid!=tid THEN

call delChannel (pid); /* 先删除该节点 */

IF @result=1000 THEN

call addChannel (tid,@name); /* 再添加到目标节点下 */

IF @result THEN

SELECT 1000 AS result;

ELSE

call addChannel (@parentid,@name); /* 添加失败的话,再添加到原来的位置*/

SELECT @result AS result;

END IF;

ELSE

SELECT @result AS result;

END IF;

ELSE

SELECT 1005 AS result;

END IF;

END IF;

SET @result=null;

SET @parentid=null;

SET @name=null;

END |

------------------------用法--------------------------

(0)得到整个树形结构:

select cid,concat(repeat("-",lv),name) from pcms_channel order by lft;

(1)获取节点的所有子孙节点:

---------------------------

如节点2的lft是2,rgt是7

select lft,rgt from pcms_channel where cid = 2;

select cid,concat(repeat("-",lv),name) from pcms_channel

where lft between 2 and 7

order by lft;

----------------------------

(2)获取节点所在路径:

---------------------------

如节点5的lft是4,rgt是5

select lft,rgt from pcms_channel where cid = 2;

select cid,concat(repeat("-",lv),name) from pcms_channel

where lft<4 and rgt>5

order by lft;

会得到从根节点到该节点的所有节点,拼接即可

---------------------------

(3)获取所有子孙节点的个数

个数= (right – left - 1) / 2

mysql 存储过程 无限分类,查看新闻/公告--[转帖]mysql存储过程实现的无限级分类,前序遍历树...相关推荐

  1. java调用visa的dll库,查看新闻/公告--[备忘]Java中,使用JNA调用Visa32.dll,控制频谱仪~~...

    Java中,使用JNA调用Visa32.dll,控制频谱仪~~ C:\Program Files\Agilent\IO Libraries Suite\ 有visa.chm,是方法和属性的说明. 首先 ...

  2. php如何对 mysql 中text类型拆分存入一个数组_PHP递归实现无限级分类,可选返回字符串和数组...

    正 文: 在一些复杂的系统中,要求对信息栏目进行无限级的分类,以增强系统的灵活性.那么PHP是如何实现无限级分类的呢?我们在本文中使用递归算法并结合mysql数据表实现无限级分类. 递归,简单的说就是 ...

  3. 无限级分类实现思路 (组织树的分级管理)

    2019独角兽企业重金招聘Python工程师标准>>> 关于该问题,暂时自己还没有深入研究,在网上找到几种解决方案,各有优缺点. 第一种方案: 使用递归算法,也是使用频率最多的,大部 ...

  4. php查找顶级分类,php 无限级分类 获取顶级分类ID,php顶级_PHP教程

    php 无限级分类 获取顶级分类ID,php顶级 有这样一个表,id是分类的ID,name是分类名称,pid是上级分类的ID. 现在有个分类ID,程序要找到它上级的上级的上级--分类的ID,简单说就是 ...

  5. php mysql 分类_php+mysql实现无限分类实例详解

    本文实例讲述了php+mysql实现无限分类的方法.分享给大家供大家参考.具体分析如下: 1.数据库通过设置父类ID来进行唯一索引,然后使用函数的递归调用实现无限分类: 2.数据库设计通过特定格式进行 ...

  6. mysql查询无限下级_示例php+mysql查询实现无限下级分类树输出

    本文实例讲述了php+mysql查询实现无限下级分类树输出.分享给大家供大家参考,具体如下: 这里介绍的php结合mysql查询无限下级树输出,其实就是无限分类.给各位整理了几个php无限分类的例子. ...

  7. php mysql无限_php+mysql实现无限分类实例详解

    php+mysql实现无限分类实例详解 fenlei($arr[$i][0]);   //$arr[$i][1]表示第$i+1个分类的id的值.进行递归,也就是把自己的id作为f_id参数把自己的子类 ...

  8. php新闻网页 毕设,【优质源码】校园新闻发布系统 php+mysql 毕设程序

    校园新闻发布系统 php+mysql 毕设程序 (无图言diao???) (左边跟我一起画个龙,右边再画一个彩虹) 先上图,再BB 首页 登陆页 个人中心页 分类页 后台管理 后台管理 计算机专业毕业 ...

  9. php修改新闻分类代码,完整的新闻无限级分类代码,可添加,删除,移动,修改

    //连接数据库教程 $link = mysql教程_connect('localhost','root','密码') or die(mysql_error()); mysql_select_db('s ...

最新文章

  1. 【转】python 字符编码与解码——unicode、str和中文:UnicodeDecodeError: 'ascii' codec can't decode...
  2. 使用 litmus 验证内存重排
  3. SAP Marketing和SAP Marketing Cloud的区别
  4. mac之自己摸索的常用快捷键总结
  5. qstring去掉特定字符_如何花式、批量且操作简单地处理字符?
  6. Linux(CentOS6.5)修改默认yum源为国内的阿里云、网易yum源
  7. 如何进入交换机配置命令窗口
  8. 非华为电脑安装华为电脑管家
  9. 4k视频分辨率的码流_4k分辨率普通码率和蓝光1080p高码率视频,到底哪个体验好?...
  10. 清除网页缓存的快捷键
  11. 如何提高在外国网站下载软件或文件的速度
  12. 牛客小白月赛2 H 武 【Dijkstra】
  13. Win7 文件加密存储操作后,如何在事后备份证书、秘钥
  14. 【高精】Oliver的成绩
  15. GNSS定位系统开发
  16. HazelEngine 学习记录 - 2D Renderer Transforms and 2D Renderer Textures
  17. YOLOV4垃圾检测召回率提升
  18. 互联网产品经理常用软件及工作平台 (转)
  19. 新研究的扩大证据显示Masimo SET(R)脉搏氧饱和度仪筛查危重型先天性心脏病(CCHD)的收益
  20. 产品经理的一些常用术语

热门文章

  1. Cloud Insight 客户案例-晨芯时代科技有限公司
  2. Alcatraz插件安装问题
  3. 我的Objective-C系列文章
  4. 文件,文件夹的创建和删除
  5. PHPsymfony
  6. C语言技巧之长度为0的数组
  7. 程序集信息设置.net
  8. 构造器初始化(三):巧用Static方法和base关键字
  9. 获取webbrowser中元素的屏幕坐标
  10. Mysql数据库大表归档操作