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


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM