多級樹形結構和sql查詢實現


https://www.jianshu.com/p/f99665266bb1

文/michaelgbw

多級樹形結構是一個應用很廣泛的數據結構,程序設計過程中,我們常常用樹形結構來表征某些數據的關聯關系,如企業上下級部門、欄目結構、商品分類等等,通常而言,這些樹狀結構需要借助於數據庫完成持久化。然而目前的各種基於關系的數據庫,都是以二維表的形式記錄存儲數據信息,因此是不能直接將樹形結構存入DBMS,設計合適的Schema及其對應的CRUD算法是實現關系型數據庫中存儲樹形結構的關鍵。

我想在生活中樹形結構應用廣泛,我們先看幾個實際的例子。

 
多級評論
 
多層隸屬關系

那么問題來了,我們應該怎么設計和實現呢,首先顯示DB端的結構,當然可以采用非關系數據庫(nosql)如mogodb,這里我們還是只討論傳統意義上的關系型數據庫mysql為例,由於關系型數據庫的特點。一張表完全可以實現,在三范式的基礎上多表采用關聯即可。

CREATE TABLE nodelist( id INT PRIMARY KEY, nodecontent VARCHAR(100), pid INT ); 

我們插入幾個測試數據進去

 
 

接下來難點來了,我們怎么一次取出和指定節點相關的所有節點呢?遞歸?循環?原理還是可以理解,但我們這次可是在用sql來進行操作。

開始百度,發現有何東西很神奇Start with...Connect By這是什么,好像從來沒見過,再一看,這個是人家Oracle的支持的,mysql並不支持啊~

好吧,自己寫吧,

delimiter / DROP FUNCTION IF EXISTS `test`.`getChild` / CREATE FUNCTION `getChild`(rootId INT) RETURNS VARCHAR(1000) BEGIN DECLARE ptemp varchar(1000); DECLARE ctemp varchar(1000); SET ptemp = '#'; SET ctemp =cast(rootId as CHAR); WHILE ctemp is not null DO SET ptemp = concat(ptemp,',',ctemp); SELECT group_concat(id) INTO ctemp FROM nodelist WHERE FIND_IN_SET(pid,ctemp)>0; END WHILE; RETURN ptemp; END 

這段sql我們稍作解釋下:

首先是DECLARE(定義一個臨時變量)

  • DECLARE語句必須用在BEGIN…END語句塊中,並且必須出現在DEGIN…END語句塊的最前面,即出現在其他語句之前。
  • DECLARE定義的變量的作用范圍僅限於DECLARE語句所在的BEGIN…END塊內及嵌套在該塊內的其他BEGIN…END塊。即是一個形參。

FIND_IN_SET函數
函數定義FIND_IN_SET(str,strlist),其實和in差不多,但這里不能用in,因為要靠這個where來判斷循環結束的條件呢。

cast
.CAST()函數的參數是一個表達式,它包括用AS關鍵字分隔的源值和目標類型。

說了一堆就是sql自定義編程,這個領域經常被我們忽視,因為我們總會把邏輯計算層放在PHP,JAVA等“第三方語言上”,

SELECT * FROM nodelist WHERE FIND_IN_SET(id, getChild(3)) 

還有一點及時如果后面的查詢條件是常量(在mysql中不需要運算獲得),則可以直接用IN, 否則要用find_in_set()函數。

 
查詢結果

這就輕松的從數據庫中取出來了,其實就是把實現的邏輯放在了sql層,這樣查詢效率自然不用說了(就進行了一次mysql IO操作)之后根據需求顯示,渲染即可,就這樣~



作者:michaelgbw
鏈接:https://www.jianshu.com/p/f99665266bb1
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM