最近在作表数据整理的时候碰到这样的一个问题,我有一张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:第一次写博客,若有不足的地方欢迎指出!