最近在作表數據整理的時候碰到這樣的一個問題,我有一張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:第一次寫博客,若有不足的地方歡迎指出!