最近在做表數據整理的時候碰到這樣的一個問題,我有一張permission表,其數據結構為樹形結構,里面有個permission_path字段用於記錄根節點到父節點的路徑(以permission_id為路徑)。
例子:假設100的父節點為10,10的父節點為1,這100的路徑為:1/10。
但現在有個問題,permission_path字段在當時並沒有處理(為空字符串),如今這個表有四五百條數據,寫代碼來改太麻煩,更別說一條條數據手動修改,不可行!
能否通過一個語句塊來自動生成路徑?顯然是可以的,因為現在的oracle、SQL SERVER2005以上版本和mysql5.0以上版本的數據庫都支持存儲過程,而存儲過程還有個比較有趣的玩法,那就是遞歸調用!用這個方法就可以快速、方便地解決上述問題。
存儲過程的概念這里就不介紹了,語句非常簡單,直接上語句(我使用的數據庫是mysql5.6),一步步解析:
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語句對數據進行操作
在幾個select語句之后,會看到if的判斷語句,在if中使用update更新表的permissiom_path的值
if ids <> '0' THEN //if語句的開頭,if 判斷條件 then 邏輯內容
end if; //if語句的結尾
while循環語句,用於循環遍歷同級數據,在這個存儲過程中也充當條件,避免無限遞歸循環
while i <= IND DO //while語句的開頭,while 判斷條件 do 邏輯內容
end while; //while語句的結尾
存儲過程的遞歸調用有兩個核心:
1、設置樹的極限深度(由於mysql數據庫的存儲過程調用中樹的深度默認為0,即不建議存儲過程調用存儲過程,所以需要這樣的設置)
SET @@max_sp_recursion_depth = 100; //絕大部分情況設置100就夠用了,除非遞歸調用的深度超過100
去掉則會報錯:
Recursive limit 0 (as set by the max_sp_recursion_depth variable)
2、調用自己
call test(substring_index(substring_index(ids,',', i), ',', -1)); //call 存儲過程名(參數)
最后,由於我的permission表的樹形結構的根節點id是0,所以我在生成存儲過程后執行的語句為
call test(0)
這樣就可以為permision表中的permission_path字段自動賦上路徑值
其實存儲過程的用法並不復雜,只要記住格式就行了,固定的格式開頭和結尾,中間的邏輯都可以是非常簡單的語句。而存儲過程的遞歸調用需要注意的地方無非是樹的深度的設置,以及防止死循環的邏輯。對於用代碼寫過遞歸調用的朋友們來說這不是什么有難度的事,如果沒有寫過遞歸調用這樣的邏輯,建議先通過代碼熟悉遞歸調用的特點以及注意事項,再來寫sql!
ps:第一次寫博客,如有不足的地方歡迎指出!