MySQL遞歸查找存儲過程

依然是SQL問題,是上篇博客(http://my.oschina.net/u/1991646/blog/731996)的升級版需求(上篇是查詢3層,這次是查詢全部):無可避免的最終仍是使用了MySQL存儲過程。html

先說明業務場景:查詢出某個節點中的全部下屬節點。sql

表結構和數據爲:服務器

id                        superior_id               
57adca6415a414043183326f                            
57adcbb915a4140431833277  57adca6415a414043183326f  
57aef2c115a48464e09f45cb  57adcbb915a4140431833277  
57af13a315a48464e09f45df  57aef2c115a48464e09f45cb  
57af541a15a44d6d4e5a54cf                            
57b014a515a44d6d4e5a54d1                            
57b13b2b15a4535f619d4a13                            
57b1f31f15a49fa67174a623                            
57b28e4e15a49fa67174a627                            
test2                     57adcbb915a4140431833277  
test3                     57adca6415a414043183326f

其中id爲主鍵,superior_id爲上級的id。性能

除去沒用的數據,關係以下:測試

57adca6415a414043183326f
   |-57adcbb915a4140431833277
     |-57aef2c115a48464e09f45cb
        |-57af13a315a48464e09f45df
     |-test2
   |-test3

實現業務場景,和之前同樣,也可使用Java代碼實現,一個考慮到性能,另外一個考慮到應用服務器的壓力,這次使用存儲過程實現。spa

存儲過程實現思路:.net

1. 須要存在一個循環遞歸條件(因爲存在遞歸,這裏經過返回結果來定義)指針

2. 遞歸時實時獲取新id做爲新查詢條件(須要使用到遊標)code

3. 使用臨時表存儲數據,臨時表經過存儲過程刪除和創建(須要存在兩個存儲過程,一個負責數據的遞歸,另外一個負責臨時表的創建和調用數據遞歸的存儲過程)htm

思路搞定,開幹!!

1. 定義數據遞歸存儲過程

-- 定義數據遞歸存儲過程:selectChildDisList
DELIMITER $$ -- MySQL分隔符定義,默認爲; 若是默認爲; 在建立存儲過程的時候會出錯,這裏應該成對存在
CREATE PROCEDURE selectChildDisList(IN id VARCHAR(1000))
BEGIN
  DECLARE cache_id VARCHAR(1000) DEFAULT '';
  DECLARE done INTEGER DEFAULT 0;
  DECLARE cursor_dis CURSOR FOR SELECT d.id
                           FROM
                             t_distribut d
                           WHERE
                             d.superior_id = id;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1; -- 含義是:若沒有數據返回,程序繼續,並將變量done設爲1
  SET @@max_sp_recursion_depth = 10;  
  INSERT INTO tmp_dis_table VALUES (id); -- 插入數據到臨時表,其中臨時表tmp_dis_table爲存儲過程selectDisList中定義 
  OPEN cursor_dis; -- 打開遊標 
  FETCH cursor_dis INTO cache_id; -- 獲取遊標當前記錄並賦值給 cache_id 變量(FETCH 獲取遊標當前指針的記錄)
  WHILE (done =0)
  DO
    CALL selectChildDisList(cache_id); -- 遞歸調用本身進行查詢
    FETCH cursor_dis INTO cache_id;
  END WHILE;
  CLOSE cursor_dis; -- 關閉遊標
END$$ -- 這個符號必定要寫這裏,否則就會出語法錯誤,具體問題還不知道
DELIMITER ;

2. 定義調用數據遞歸存儲過程的存儲過程

-- 定義調用數據遞歸存儲過程的存儲過程:selectDisList
DELIMITER $$
CREATE PROCEDURE selectDisList(IN id VARCHAR(1000))
BEGIN
  -- 這裏經過臨時表來獲取獲得的結果集數據
  DROP TEMPORARY TABLE IF EXISTS tmp_dis_table; 
  CREATE TEMPORARY TABLE tmp_dis_table(
	  disId VARCHAR(1000)
	);
  DELETE FROM tmp_dis_table;
  CALL selectChildDisList(id);
  SELECT DISTINCT disId
FROM
  tmp_dis_table ORDER BY disId;
END$$ 
DELIMITER ;

3. 存儲過程的調用

CALL selectDisList('id');

數據測試:

根據上述的數據進行測試,首先測試查找id爲'57adca6415a414043183326f'下的數據,結果爲:

再測試查找id爲'57adca6415a414043183326f'下的數據,結果爲:

通過對照,測試結果沒有問題,到此爲止,一切OK。

仍然存在不理解的地方:

1. DELIMITER 中定義分隔符必定要寫在  END後

2. SET @@max_sp_recursion_depth = 10; 此處的含義不是很理解。若是沒有還會拋出

參考博文:http://blog.csdn.net/u012501459/article/details/12945267

                   http://www.cnblogs.com/sk-net/archive/2011/09/07/2170224.html

純手打,歡迎拍磚,也但願大哥大姐們能解決我上述不理解的疑惑,感謝~

轉載請指明出處:http://my.oschina.net/u/1991646/blog/733531

相關文章
相關標籤/搜索