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

歡迎訪問 生活随笔!

生活随笔

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

数据库

PHP和MySQL处理树状、分级、无限分类、分层数据的方法

發布時間:2025/3/13 数据库 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PHP和MySQL处理树状、分级、无限分类、分层数据的方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章標題中的多個詞語表達的其實是一個意思,就是遞歸分類數據,分級數據非常類似數據結構中的樹狀結構,即每個節點有自己的孩子節點,孩子結點本身也是父親節點。這是一個遞歸、分層形式??梢苑Q之為樹形層級數據。 層級數據結構是編程語言中非常普通的一種數據結構,它代表一系列的數據每一項都有一個父親節點(除了根節點)和其他多個孩子結點。WEB開發人員使用層級數據結構用于非常多的場景,包括內容管理系統CMS、論壇主題、郵件列表,還有電子商務網站的產品分類等。 本文章主要介紹了使用PHP和MYSQL來管理分級數據的方法,在其中將給出兩種最流行的分級數據模型:
  • 鄰接表模型
  • 嵌套集合模型

鄰接表模型用于分層數據

鄰接表模型是一種分級數據模型,其中每個節點有一個指向其父親的指針(根節點該指針為空值),使用下面的SQL語句將建立該結構并插入測試數據: -- ---------------------------------------------------------- -- 表的結構 `category` --CREATE TABLE IF NOT EXISTS `category` (`category_id` int(10) NOT NULL AUTO_INCREMENT,`category_name` varchar(50) NOT NULL,`parent_id` int(10) DEFAULT NULL,PRIMARY KEY (`category_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=15 ;-- -- 轉存表中的數據 `category` --INSERT INTO `category` (`category_id`, `category_name`, `parent_id`) VALUES (1, 'A', NULL), (2, 'B', 1), (3, 'C', 1), (4, 'D', 1), (5, 'E', 2), (6, 'F', 2), (7, 'I', 4), (8, 'G', 5), (9, 'H', 5), (10, 'J', 7), (11, 'K', 10), (12, 'L', 10); 建立完成后,數據庫中存在了數據,并且分類圖是這樣的,每個節點為(關鍵字:數據庫ID): parent_id就是它的父節點的ID號,這種方法非常簡單,因為能很容易的看清楚父子關系。使用以下的簡單PHP函數代碼可以很容易的輸出樹狀路徑: <?phpfunction get_path($category_id) {$con = mysql_connect("localhost","root","123456");if (!$con) {die('數據庫連接失敗: ' . mysql_error());}mysql_select_db('test', $con); // 查找當前節點的父節點的ID,這里使用表自身與自身連接實現$sql = "SELECT c1.parent_id, c2.category_name AS parent_name FROM category AS c1LEFT JOIN category AS c2 ON c1.parent_id=c2.category_id WHERE c1.category_id='$category_id' ";//echo $sql."<br>";//測試把SQL打印出來,拿到數據庫執行一下看看結果$result = mysql_query($sql);$row = mysql_fetch_array($result);//現在$row數組存了父親節點的ID和名稱信息// 將樹狀路徑保存在數組里面$path = array();//如果父親節點不為空(根節點),就把父節點加到路徑里面if ($row['parent_id']!=NULL) {//將父節點信息存入一個數組元素$parent[0]['category_id'] = $row['parent_id'];$parent[0]['category_name'] = $row['parent_name'];//遞歸的將父節點加到路徑中$path = array_merge(get_path($row['parent_id']), $parent);}return $path; }//根據上面的圖可以看出,K的ID是11,我們就用它來測試路徑 $path = get_path(11); echo "<h2>路徑數組:</h2>"; echo "<pre>"; print_r($path); echo "</pre>"; //將路徑到根節點的路徑打印出來 //打印結果:J>I>D>A> echo "<h2>向根節點打印路徑:</h2>";for ($i=count($path)-1; $i>=0; $i--) {echo $path[$i]['category_name']. '>'; }?> 運行結果截圖: 由此可以知道怎樣找到一個葉子節點(沒有孩子的節點)到根節點的路徑,下面來看怎樣從根節點往下來遍歷層級結構,通過節點的層級關系來打印所有的節點: <?php function display_children($category_id, $level) {$con = mysql_connect("localhost","root","123456");if (!$con) {die('數據庫連接失敗: ' . mysql_error());}mysql_select_db('test', $con); // 獲得當前節點的所有孩子節點(直接孩子,沒有孫子)$result = mysql_query("SELECT * FROM category WHERE parent_id='$category_id'");// 遍歷孩子節點,打印節點while ($row = mysql_fetch_array($result)) {// 根據層級,按照縮進格式打印節點的名字// 這里只是打印,你可以將以下代碼改成其他,比如把節點信息存儲起來echo str_repeat('--',$level) . $row['category_name'] . "<br/>";// 遞歸的打印所有的孩子節點display_children($row['category_id'], $level+1);} }//根節點是A:1我們就用它來打印所有的節點 display_children(1, 0); ?> 該段代碼運行結果: 然而,鄰接表模型(每個節點存儲父親節點信息)有它的劣勢,首先使用數據庫的查詢語句很難直接實現它,需要借助PHP代碼實現。SQL語句需要你知道節點位于哪一個層級。并且每個樹層是使用SQL的自我表連接實現的,這意味著樹的每一層處理都會降低數據庫的性能。 刪除節點的過程也會導致一些問題,如果只刪除了某個節點它卻有孩子,結果是它的孩子成了孤兒(就是沒有父親了),真正的體現就是,這些孩子節點從樹中相當于“消失了”。

嵌套集合模型用于樹形分層結構數據

嵌套集合模型,也叫做先根遍歷樹算法,也是一種處理樹形層級數據的方法。代替節點間的父子關系,層級使用嵌套的容器的集合來表示,其中每個節點具有兩個值,一個left,一個right。以下是例子的模擬圖: 決定left和right的值的過程是從左到右進行的,首先給left賦值,讓后向下遍歷節點的孩子們,最后才能得到節點的right的值。SQL語句如下所示: CREATE TABLE category (category_id INT(10) AUTO_INCREMENT PRIMARY KEY,category_name VARCHAR(50) NOT NULL,lft INT(10) NOT NULL,rgt INT(10) NOT NULL ); 現在可以用一句SQL查詢得到整個樹的節點: SELECT * FROM category WHERE lft BETWEEN 1 AND 14 ORDER BY lft ASC 在本SQL中的兩個數字值1和14就是根節點的left和right值。類似的如果想得到某個節點的所有孩子節點,只需要將該SQL語句的1和14替換成本節點的left和right值就可以了。例如,如果想得到所有男人的衣服,可以用下面的SQL語句: SELECT * FROM category WHERE lft BETWEEN 2 AND 7 ORDER BY lft ASC 想找到一條到某個節點的路徑,用一條SQL語句就可以搞定: SELECT * FROM category WHERE lft < 9 AND rgt > 10 ORDER BY lft ASC 請仔細觀察一下一些葉子節點到根節點的路徑。就會發現所有的祖先都有更小的左值和更大的右值。本例子中一條到裙子分類的路徑被取出。觀察一下裙子的所有left值都小于9,right值都大于10,其他的非祖先節點都不滿足該要求。 盡管嵌套集合模型更加復雜并且有些難以理解,它有非常多的優勢。它不需要依賴其他資源(比如PHP代碼),也不需要遞歸。同時,數據庫查詢語句非常的簡單,大多數用一條SQL語句就可以搞定。這些特性都能夠顯著的增加應用程序的性能,使得它能夠用可接受的速度來處理復雜的層級結構。 然而萬事皆無完美,更新該層級結構(增加或刪除節點)卻更加的復雜,并且可能會非常慢。 增加一個節點到層級結構的方法: 將一個節點插入到層級數據中,需要整個樹很多節點的left和right值的更新。例如,如果你想將一個男士運動鞋的分類插入到男性衣服的短褲后面。那么所有你必須將大于6的所有left和right值都增加2。為什么呢?因為短褲的right值是6,那你就必須將你的新分類的left和right值設定為7和8,當然,以下兩條SQL就可以解決: UPDATE category SET rgt=rgt+2 WHERE rgt>6 UPDATE category SET lft=lft+2 WHERE lft>6 現在樹中間已經有空隙用來插入新分類了,用一條SQL插入該節點: INSERT INTO category (category_name,lft,rgt) VALUES ('Sneakers', '7', '8') 樹形層級數據中刪除一個節點的方法: 在層級集合模型中刪除一個節點的方法,比在鄰接表中相同的操作稍微難一些。不同的操作的復雜程度是不同的,比如刪除一個葉子節點和一個帶孩子節點就很不同。 要刪除一個葉子節點,先將所有left和right大于該節點left和right值的節點的left和right減去2,然后再刪除該節點。以下使用SQL實現該過程: UPDATE category SET lft=lft-2 WHERE lft>5 UPDATE category SET rgt=rgt-2 WHERE rgt>6 DELETE FROM category WHERE lft='5' AND rgt='6' 該例子中短褲節點被刪除了。 如果要刪除的節點有孩子節點的話,刪除過程會多一個步驟: 比如我們刪除男性衣服分類的時候: UPDATE category SET lft=lft-1, rgt=rgt-1 WHERE lft>2 AND rgt<7 UPDATE category SET lft=lft-2 WHERE lft>7 UPDATE category SET rgt=rgt-2 WHERE rgt>7 DELETE FROM category WHERE lft='2' AND rgt='7'

哪種模型對于處理樹形分層數據更好?

哪種情況更好呢,看情況。如果需要一個更加靈活的模型,更容易更新,就用鄰接表模型吧。如果分類構成了一棵復雜的數,并且更新不需要很頻繁,用嵌套集合模型肯定是上上之選。 本文內容翻譯自:訪問,其中原文中的代碼有些問題,本人添加了測試數據并改正了代碼。

轉載于:https://www.cnblogs.com/crazyant/archive/2012/08/20/2823885.html

總結

以上是生活随笔為你收集整理的PHP和MySQL处理树状、分级、无限分类、分层数据的方法的全部內容,希望文章能夠幫你解決所遇到的問題。

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