php和mysql處理樹狀_分級_無限分類_分層數據的方法_PHP和MySQL處理樹狀、分級、無限分類、分層數據的方法...

文章標題中的多個詞語表達的其實是一個意思,就是遞歸分類數據,分級數據非常類似數據結構中的樹狀結構,即每個節點有自己的孩子節點,孩子結點本身也是父親節點。這是一個遞歸、分層形式。可以稱之為樹形層級數據。

層級數據結構是編程語言中非常普通的一種數據結構,它代表一系列的數據每一項都有一個父親節點(除了根節點)和其他多個孩子結點。WEB開發人員使用層級數據結構用于非常多的場景,包括內容管理系統CMS、論壇主題、郵件列表,還有電子商務網站的產品分類等。

本文章主要介紹了使用PHP和MYSQL來管理分級數據的方法,在其中將給出兩種最流行的分級數據模型:

鄰接表模型

嵌套集合模型

鄰接表模型用于分層數據

鄰接表模型是一種分級數據模型,其中每個節點有一個指向其父親的指針(根節點該指針為空值),使用下面的SQL語句將建立該結構并插入測試數據:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

表的結構

`

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函數代碼可以很容易的輸出樹狀路徑:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

function

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 c1

LEFT JOIN category AS c2

ON c1.parent_id=c2.category_id

WHERE c1.category_id='$category_id' "

;

//echo $sql."
";//測試把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

"

路徑數組:

"

;

echo

"

"

;

print_r

(

$path

)

;

echo

"

"

;

//將路徑到根節點的路徑打印出來

//打印結果:J>I>D>A>

echo

"

向根節點打印路徑:

"

;

for

(

$i

=

count

(

$path

)

-

1

;

$i

>=

0

;

$i

--

)

{

echo

$path

[

$i

]

[

'category_name'

]

.

'>'

;

}

?>

由此可以知道怎樣找到一個葉子節點(沒有孩子的節點)到根節點的路徑,下面來看怎樣從根節點往下來遍歷層級結構,通過節點的層級關系來打印所有的節點:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

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'

]

.

"
"

;

// 遞歸的打印所有的孩子節點

display_children

(

$row

[

'category_id'

]

,

$level

+

1

)

;

}

}

//根節點是A:1我們就用它來打印所有的節點

display_children

(

1

,

0

)

;

?>

然而,鄰接表模型(每個節點存儲父親節點信息)有它的劣勢,首先使用數據庫的查詢語句很難直接實現它,需要借助PHP代碼實現。SQL語句需要你知道節點位于哪一個層級。并且每個樹層是使用SQL的自我表連接實現的,這意味著樹的每一層處理都會降低數據庫的性能。

刪除節點的過程也會導致一些問題,如果只刪除了某個節點它卻有孩子,結果是它的孩子成了孤兒(就是沒有父親了),真正的體現就是,這些孩子節點從樹中相當于“消失了”。

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

嵌套集合模型,也叫做先根遍歷樹算法,也是一種處理樹形層級數據的方法。代替節點間的父子關系,層級使用嵌套的容器的集合來表示,其中每個節點具有兩個值,一個left,一個right。

決定left和right的值的過程是從左到右進行的,首先給left賦值,讓后向下遍歷節點的孩子們,最后才能得到節點的right的值。SQL語句如下所示:

1

2

3

4

5

6

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'

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

哪種情況更好呢,看情況。如果需要一個更加靈活的模型,更容易更新,就用鄰接表模型吧。如果分類構成了一棵復雜的數,并且更新不需要很頻繁,用嵌套集合模型肯定是上上之選。

本文內容翻譯自:訪問,其中原文中的代碼有些問題,本人添加了測試數據并改正了代碼。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/397725.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/397725.shtml
英文地址,請注明出處:http://en.pswp.cn/news/397725.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LeetCode 70. Climbing Stairs

You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? 一開始想用排列組合的方式&#xff0c;但是公式不太好些&#xff0c;后來想用遞歸的方式&#x…

04 java 基礎:數據類型

java 數據類型&#xff1a;基本類型與引用類型 基本類型&#xff1a;數值型&#xff0c;其中數值型分為整型、浮點型&#xff0c;整型包括 byte、short 、int、long &#xff0c;默認為 int 類型。浮點類型分為單精度、雙精度&#xff0c;分為 float、double &#xff0c;默認為…

Git 遠程倉庫分支管理

目錄 目錄速查表關聯遠程代碼倉庫克隆遠程倉庫 分支管理創建分支 切換分支合并分支刪除分支解決沖突速查表 指令作用git branch查看分支git branch newBranchName創建分支git checkout branchName切換分支giit checkout -b newBranchName創建切換分支git merge branchName合并分…

call,apply

1.call要逐個傳入參數 2apply方法的必須 function curry(fn){var argsArray.prototype.slice.call(arguments,1);return function(){var innerArgsArray.prototype.slice.call(arguments);var finalArgsargs.concat(innerArgs);console.log(finalArgs);return fn(finalArgs);//…

2018美團CodeM編程大賽 Round A Problem 2 下棋 【貪心】

應該一眼看出來是貪心題&#xff0c;然后想最優解是什么。正確的貪心策略是【原棋盤上每個位置的棋子】都往最近的左邊【目標棋盤上棋子】移動&#xff0c;如果左邊沒有棋子了那就閑置最后處理&#xff0c;如果目標棋盤在該位置上也有棋子&#xff0c;那就算距離為0&#xff08…

idea清理svn信息_IntelliJ IDEA SVN的賬號修改 信息清除

來到編譯器的setting設置 搜索subversion 點擊subversion 找到下面的clear auth...按鈕,點擊一下 就可以了…如果我們不小心輸入svn賬號錯誤的話,后面就一直提示認證失敗,不能checkout代碼. 這個是因為svn把你輸入的賬號進行了緩存. 如果我們想重新輸入新的賬號,必須要清除緩存…

同步手繪板——json

JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。它基于ECMAScript的一個子集。 JSON采用完全獨立于語言的文本格式&#xff0c;但是也使用了類似于C語言家族的習慣&#xff08;包括C、C、C#、Java、JavaScript、Perl、Python等&#xff09;。這些特性使JSON成為…

[HNOI2008]玩具裝箱TOY

洛谷題目連接:[HNOI2008]玩具裝箱TOY 題目描述 P教授要去看奧運&#xff0c;但是他舍不下他的玩具&#xff0c;于是他決定把所有的玩具運到北京。他使用自己的壓縮器進行壓縮&#xff0c;其可以將任意物品變成一堆&#xff0c;再放到一種特殊的一維容器中。P教授有編號為1...N的…

C語言-結構體內存對齊

C語言結構體對齊也是老生常談的話題了。基本上是面試題的必考題。內容雖然很基礎&#xff0c;但一不小心就會弄錯。寫出一個struct&#xff0c;然后sizeof&#xff0c;你會不會經常對結果感到奇怪&#xff1f;sizeof的結果往往都比你聲明的變量總長度要大&#xff0c;這是怎么回…

nginx 二進制包安裝mysql_二進制安裝mysql5.7

下載地址&#xff1a;https://downloads.mysql.com/archives/community/[rootlocalhost soft]# lsmysql-5.7.17-linux-glibc2.5-x86_64.tar.gz nginx-1.12.2 nginx-1.12.2.tar.gz[rootlocalhost soft]#1.詳細描安裝的過程1.1關閉防火墻systemctl stop firewalld.service #停止f…

.NET 類型(Types)的那些事

引言 您是.Net工程師&#xff1f;那 .NetFramework中的類型您知道有三大類嗎&#xff1f;&#xff08;除了引用類型和值類型&#xff0c;還有&#xff1f;&#xff09; 引用類型一定在“堆”上&#xff0c;值類型一定在“棧”上&#xff1f; 那引用類型在內存中的布局細節您又知…

幾種去除數組中重復元素的方法、數組去重

工作中遇到的一個問題&#xff0c;就是去除數組中重復的元素&#xff0c;記錄一下幾種有效的方法&#xff1a; 第一種思路&#xff1a;遍歷要刪除的數組arr, 把元素分別放入另一個數組tmp中&#xff0c;在判斷該元素在arr中不存在才允許放入tmp中。 <!DOCTYPE html> <…

MongoDB學習使用

一、什么是MongoDB&#xff1f; MongoDB是一個高性能&#xff0c;開源&#xff0c;無模式的文檔型數據庫&#xff0c;是當前NoSql數據庫中比較熱門的一種。它在許多場景下可用于替代傳統的關系型數據庫或鍵/值存儲方式&#xff0c; NoSql&#xff0c;全稱是 Not Only Sql,指的是…

域賬號更改密碼之后代理需要重新配置

在使用域賬號的時候&#xff0c;如果需要配置賬戶和密碼&#xff0c;那么最好記錄下來&#xff0c;否則將來找不到就很尷尬了。 我遇到的問題是&#xff0c;因為在另外一臺電腦配置了域賬號&#xff0c;用來聯網&#xff0c;提供網絡給visual studio 1.Firefox 這個代理的賬號…

wcf精通1-15

隨筆- 197 文章- 0 評論- 3407 十五天精通WCF——第一天 三種Binding讓你KO80%的業務 轉眼wcf技術已經出現很多年了&#xff0c;也在.net界混的風生水起&#xff0c;同時.net也是一個高度封裝的框架&#xff0c;作為在wcf食物鏈最頂端的我們所能做的任務已經簡單的不能再簡單…

python如何實現共享報表系統_使用python來實現報表自動化-阿里云開發者社區

xlwt 常用功能xlrd 常用功能xlutils 常用功能xlwt寫Excel時公式的應用xlwt寫入特定目錄(路徑設置)xlwt Python語言中&#xff0c;寫入Excel文件的擴展工具。可以實現指定表單、指定單元格的寫入。支持excel03版到excel2013版。使用時請確保已經安裝python環境。百度百科xlrd Py…

去除inline-block元素間間距的N種方法

這篇文章發布于 2012年04月24日&#xff0c;星期二&#xff0c;22:38&#xff0c;歸類于 css相關。 閱讀 147771 次, 今日 52 次 by zhangxinxu from http://www.zhangxinxu.com 本文地址&#xff1a;http://www.zhangxinxu.com/wordpress/?p2357 一、現象描述 真正意義上的in…

Docker深入淺出2

Docker系統架構 Docker使用客戶端-服務端&#xff08;c/s&#xff09;架構模式&#xff0c;使用遠程api來管理和創建Docker容器。 docker容器通過Docker鏡像來創建。 容器與鏡像的關系類似于面向對象編程中的對象與類的關系 Docker面向對象容器對象鏡像類加速器配置&#xff1a…

mysql安裝包下載密碼_MySQL解壓包的安裝與下載的圖文教程

這篇文章主要為大家詳細介紹了mysql解壓包的安裝基礎教程&#xff0c;具有一定的參考價值&#xff0c;感興趣的小伙伴們可以參考一下由于換了新電腦&#xff0c;所以的環境都要到新電腦去配置。突然發現mysql的配置忘了&#xff0c;然后百度又重新來一遍。特地寫一篇文章記錄一…

php 扒取網頁數據

扒取方法 public function index(){$url http://www.dytt8.net/;// $url Public/txt/movies.txt;$content file_get_contents($url);$content iconv("gb2312", "utf-8//IGNORE",$content);$reg "|<div class\"co_content2\">(.*…