存儲過程的遞歸調用(樹形結構路徑的快速生成)

       最近在作表數據整理的時候碰到這樣的一個問題,我有一張permission表,其數據結構爲樹形結構,裏面有個permission_path字段用於記錄根節點到父節點的路徑(以permission_id爲路徑)。mysql

  例子:假設100的父節點爲10,10的父節點爲1,這100的路徑爲:1/10。sql

 

  但如今有個問題,permission_path字段在當時並無處理(爲空字符串),現在這個表有四五百條數據,寫代碼來改太麻煩,更別說一條條數據手動修改,不可行!數據庫

  可否經過一個語句塊來自動生成路徑?顯然是能夠的,由於如今的oracle、SQL SERVER2005以上版本和mysql5.0以上版本的數據庫都支持存儲過程,而存儲過程還有個比較有趣的玩法,那就是遞歸調用!用這個方法就能夠快速、方便地解決上述問題。數據結構

  存儲過程的概念這裏就不介紹了,語句很是簡單,直接上語句(我使用的數據庫是mysql5.6),一步步解析:oracle

CREATE PROCEDURE test(IN parent int)
BEGIN 
DECLARE ids VARCHAR(255) DEFAULT '0';   
DECLARE IND INT;
DECLARE i INT DEFAULT 1;
DECLARE path VARCHAR(255);
SELECT GROUP_CONCAT(t.permission_id) INTO ids from system_permissions t where t.permission_parent = parent;
SELECT COUNT(t.*) INTO IND from system_permissions t where t.permission_parent = parent;
SELECT t.permission_path INTO path from system_permissions t where t.permission_id = parent;
if ids <> '0' THEN
UPDATE system_permissions set permission_path = CONCAT(path,'/',parent) where permission_parent = parent;
SET @@max_sp_recursion_depth = 100;  
while i <= IND  DO
call test(substring_index(substring_index(ids,',', i), ',', -1));
set i = i + 1;
end while;
end if;
end

  先介紹基本語法:函數

create procedure test(IN p1 int,IN p2 varchar2(10))      //create procedure 函數名(IN 參數1 類型,IN 參數2 類型),英文部分爲固定寫法,
                                    中文部分爲自定義,其中類型只能使用數據庫存在的類型
  begin   //標識着存儲過程邏輯的開始     語句內容  //邏輯、語句都寫在此處   end  //標識着存儲過程邏輯的結束
DECLARE 聲明變量
DECLARE ids VARCHAR(255) DEFAULT '0';    //DECLARE 表示聲明一個變量,該變量類型爲varchar(255),默認值爲0

把變量都定義好後,就可使用sql語句對數據進行操做spa

在幾個select語句以後,會看到if的判斷語句,在if中使用update更新表的permissiom_path的值code

if ids <> '0' THEN    //if語句的開頭,if 判斷條件 then
  邏輯內容
end if;    //if語句的結尾

while循環語句,用於循環遍歷同級數據,在這個存儲過程當中也充當條件,避免無限遞歸循環blog

while i <= IND  DO  //while語句的開頭,while 判斷條件 do
  邏輯內容
end while;    //while語句的結尾

存儲過程的遞歸調用有兩個核心:遞歸

一、設置樹的極限深度(因爲mysql數據庫的存儲過程調用中樹的深度默認爲0,即不建議存儲過程調用存儲過程,因此須要這樣的設置)

SET @@max_sp_recursion_depth = 100;   //絕大部分狀況設置100就夠用了,除非遞歸調用的深度超過100

去掉則會報錯:

Recursive limit 0 (as set by the max_sp_recursion_depth variable)

二、調用本身

call test(substring_index(substring_index(ids,',', i), ',', -1));  //call 存儲過程名(參數)

最後,因爲個人permission表的樹形結構的根節點id是0,因此我在生成存儲過程後執行的語句爲

call test(0)

這樣就能夠爲permision表中的permission_path字段自動賦上路徑值

其實存儲過程的用法並不複雜,只要記住格式就好了,固定的格式開頭和結尾,中間的邏輯均可以是很是簡單的語句。而存儲過程的遞歸調用須要注意的地方無非是樹的深度的設置,以及防止死循環的邏輯。對於用代碼寫過遞歸調用的朋友們來講這不是什麼有難度的事,若是沒有寫過遞歸調用這樣的邏輯,建議先經過代碼熟悉遞歸調用的特色以及注意事項,再來寫sql!

ps:第一次寫博客,若有不足的地方歡迎指出!

相關文章
相關標籤/搜索