如何用mysql存一棵樹 如何在資料庫中儲存一棵樹

2021-10-17 19:22:11 字數 2957 閱讀 2885

方法一要儲存於資料庫中,最簡單直接的方法,就是儲存每個元素的父節點id。

暫且把這種方法命名依賴父節點法,因此表結構設計如下:

儲存的資料如下格式:

這種結構下,如果查詢某乙個節點的直接子節點,十分容易,比如要查詢d節點的子節點。

如果要插入某個節點,比如在d節點下,再次插入乙個m節點。

只需要如下sql:

這種結構在查詢某個節點的所有子節點,就稍顯複雜,無論是select還是delete都可能涉及到獲取所有子節點的問題。比如要刪除乙個節點並且該節點的子節點也要全部刪除,那麼首先要獲得所有子節點的id,因為子節點並不只是直接子節點,還可能包含子節點的子節點。比如刪除d節點及其子節點,必須先查出d節點下的所有子節點,然後再做刪除,sql如下:

如果是只刪除d節點,對於其它節點不做刪除而是做提公升,那麼必須先修改子節點的parentid,然後才能刪除d節點。

正如上面演示的,對於這種依賴父節點法,最大的缺點就是無法直接獲得某個節點的所有子節點。因此如果要select所有的子節點,需要繁瑣的步驟,這不利於做聚合操作。

對於某些資料庫產品,支援遞迴查詢語句的,比如微軟的sql server,可以使用cte技術實現遞迴查詢。比如,要查詢d節點的所有子節點。只需要如下語句:

但是對於那些不支援遞迴查詢的資料庫來說,實現起來就比較複雜了。

方法二還有一種比較土的方法,就是儲存路徑。暫且命名為路徑列舉法。

這種方法,將儲存根結點到每個節點的路徑。

這種資料結構,可以一眼就看出子節點的深度。

如果要查詢某個節點下的子節點,只需要根據path的路徑去匹配,比如要查詢d節點下的所有子節點。

或者出於效率考慮,直接寫成

如果要做聚合操作,也很容易,比如查詢d節點下一共有多少個節點。

select count(*) from tree2 where path like '1/4/%';

要插入乙個節點,則稍微麻煩點。要插入自己,然後查出父節點的path,並且把自己生成的id更新到path中去。比如,要在l節點後面插入m節點。

首先插入自己m,然後得到乙個nodeid比如nodeid=13,然後m要插入到l後面,因此,查出l的path為1/4/8/12/,因此update m的path為1/4/8/12/13

這種方法有乙個明顯的缺點就是path欄位的長度是有限的,這意味著,不能無限制的增加節點深度。因此這種方法適用於儲存小型的樹結構。

方法三下面介紹一種方法,稱之為閉包錶。

該方法記錄了樹中所有節點的關係,不僅僅只是直接父子關係,它需要使用2張表,除了節點表本身之外,還需要使用1張表來儲存節祖先點和後代節點之間的關係(同時增加一行節點指向自身),並且根據需要,可以增加乙個字段,表示深度。因此這種方法資料量很多。設計的表結構如下:

tree3表:

noderelation表:

如例子中的樹,插入的資料如下:

tree3表的資料

noderelation表的資料

可以看到,noderelation表的資料量很多。但是查詢非常方便。比如,要查詢d節點的子元素

只需要要查詢節點d的直接子節點,則加上depth=1

要查詢節點j的所有父節點,sql:

如果是插入乙個新的節點,比如在l節點後新增子節點m,則插入的節點除了m自身外,還有對應的節點關係。即還有哪些節點和新插入的m節點有後代關係。這個其實很簡單,只要和l節點有後代關係的,和m節點必定會有後代關係,並且和l節點深度為x的和m節點的深度必定為x+1。因此,在插入m節點後,找出l節點為後代的那些節點作為和m節點之間有後代關係,插入到資料表。

在某些並不需要使用深度的情況下,甚至可以不需要depth欄位。

如果要刪除某個節點也很容易,比如,要刪除節點d,這種情況下,除了刪除tree3表中的d節點外,還需要刪除noderelation表中的關係。

首先以d節點為後代的關係要刪除,同時以d節點的後代為後代的這些關係也要刪除:

這種刪除方法,雖然徹底,但是它也刪除了d節點和它原本的子節點的關係。

如果只是想割裂d節點和a節點的關係,而對於它原有的子節點的關係予以保留,則需要加入限定條件。

限制要刪除的關係的祖先不以d為祖先,即如果這個關係以d為祖先的,則不用刪除。因此把上面的sql加上條件。

上面的sql用文字描述就是,查詢出d節點的後代,如果乙個關係的祖先不屬於d節點的後代,並且這個關係的後代屬於d節點的後代,就刪除它。

這樣的刪除,保留了d節點自身子節點的關係,如上面的例子,實際上刪除的節點關係為:

如果要刪除節點h,則為

總結:上面主要講了3種方式,各有優點缺點。可以根據實際需要,選擇合適的資料模型。

如何用mysql存一棵樹 如何在資料庫中儲存一棵樹

方法一要儲存於資料庫中,最簡單直接的方法,就是儲存每個元素的父節點id。暫且把這種方法命名依賴父節點法,因此表結構設計如下 儲存的資料如下格式 這種結構下,如果查詢某乙個節點的直接子節點,十分容易,比如要查詢d節點的子節點。select from tree1 where parentid 4 如果要...

如何判斷一棵樹是不是另一棵樹的子樹

package suanfatest class treenode treenode int value treenode int value,treenode leftchild,treenode rightchild public int getvalue public void setvalu...

一棵樹是否為另一棵樹的子結構

輸入兩顆二叉樹a,b,判斷b是不是a的子結構。問題描述 給定兩個二叉樹的根節點,判斷第二樹是否是第乙個樹的子樹,如果是返回1,否則返回0.拿第二個樹的每個節點去和第乙個樹做匹配,如果某個節點匹配成功,就接著往下匹配,否則重新從第二個樹的的根節點開始。注意區別 測試用例 樹1 42 6 1 3 5 7...