日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

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

發布時間:2024/9/19 数据库 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 存储过程 无限分类,查看新闻/公告--[转帖]mysql存储过程实现的无限级分类,前序遍历树... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原理說明可以看這個帖子:

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存储过程实现的无限级分类,前序遍历树...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。