原文鏈接:https://www.zhoubotong.site/post/92.html 通常我們直接通過遞歸查詢來達到實現子節點數據獲取的需求,這裡不談存儲過程的實現,存儲過程普通賬號有許可權限制,通常也不易於開發者維護,這裡介紹下純mysql遞歸實現的方式:測試數據可以通過之前的一篇文章來模擬。 ...
通常我們直接通過遞歸查詢來達到實現子節點數據獲取的需求,這裡不談存儲過程的實現,存儲過程普通賬號有許可權限制,通常也不易於開發者維護,
這裡介紹下純mysql遞歸實現的方式:
測試數據可以通過之前的一篇文章來模擬。在正式介紹實現之前,我們先瞭解下幾個mysql實現涉及的相關知識點:
Mysql用戶變數
用戶變數無需聲明,直接賦值就行。用戶變數名不區分大小寫。名稱的最大長度為64個字元。常用的賦值方式有:
方式一:使用 SET 賦值。
可以使用形如 set @變數名=變數值 或者 set@變數名:=變數值 的方式賦值。
SET @var_name = expr [, @var_name = expr] ... 或 SET @var_name := expr [, @var_name := expr] ...
方式二:使用 select 賦值。
select @變數名:=變數值 select @變數名:=欄位名 from table where ... limit 1;
繼續舉個例子,表記錄如下:
註意: 通過查詢表給變數賦值時,需保證查詢結果只有一條記錄,如上result2的結果集這種查詢了2條。
另外再介紹本文實現中涉及的另外2個mysql函數,這裡就簡單介紹下:
if(express1,express2,express3)條件語句:
if語句類似三目運算符,當exprss1成立時,執行express2,否則執行express3;
FIND_IN_SET(str,strlist),str 要查詢的字元串,strlist 欄位名 參數以”,”分隔 如 (1,2,3,6),查詢欄位(strlist)中包含(str)的結果.
concat_ws()函數, 表示concat with separator,即有分隔符的字元串連接:
select concat_ws(',','11','22',NULL); 返回 11,22。
下麵進入本文正題,查詢當前節點下的所有子節點:
select id from ( select t1.id, if( find_in_set(pid, @pids) > 0, @pids := CONCAT_WS(',',@pids, id), 0 ) as ischild from ( select id, pid from city t order by id ) t1, ( select @pids := 11 ) t2 ) t3 where ischild != 0;
上面我們查詢節點id=11(武漢市)下的所有節點。上面語句看似複雜,其實不難理解,我們來分下該sql是怎麼實現結果集的。
我們先從最裡面的子查詢分析:
我們看到第二個from後面是跟了兩張表:t1和t2, t2是一個用戶變數,其結果集作為t2,
,t1表很好理解就是city的所有記錄作為表t1,我們再看t3表是什麼?
上面高亮部分即為t3的結果集,其目的就是將當前要查詢的子節點id用逗號連接,
如果pid值在@pids中,則設置@pids用其用戶變數+id逗號連接組成新欄位ischild。因為@pids查詢到匹配記錄就重新賦值了,
所以大家不難理解其滿足條件下的子節點。
上面就是關於遞歸查詢的實現。當然還有另外一種查法:
SELECT t1.id FROM (SELECT id,pid FROM city WHERE pid IS NOT NULL) t1, (SELECT @pid := 11) t2 WHERE FIND_IN_SET(pid, @pid) > 0 AND @pid := concat(@pid, ',', id) -- union select id from city where id = 11 order by id;
如果想查詢結果包含自身ID(如上面的id=11),加上後邊的union即可。