存储过程的递归调用(树形结构路径的快速生成)

Posted 丰兰月

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了存储过程的递归调用(树形结构路径的快速生成)相关的知识,希望对你有一定的参考价值。

       最近在做表数据整理的时候碰到这样的一个问题,我有一张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、设置树的极限深度,使用场景一般为存储过程中调用存储过程

SET @@max_sp_recursion_depth = 100;   //绝大部分情况设置100就够用了,除非递归调用的深度超过100

2、调用自己

call test(substring_index(substring_index(ids,,, i), ,, -1));  //call 存储过程名(参数)

最后,由于我的permission表的树形结构的根节点id是0,所以我在生成存储过程后执行的语句为

call test(0)

这样就可以为permision表中的permission_path字段自动赋上路径值

其实存储过程的用法并不复杂,只要记住格式就行了,固定的格式开头和结尾,中间的逻辑都可以是非常简单的语句。而存储过程的递归调用需要注意的地方无非是树的深度的设置,以及防止死循环的逻辑。对于用代码写过递归调用的朋友们来说这不是什么有难度的事,如果没有写过递归调用这样的逻辑,建议先通过代码熟悉递归调用的特点以及注意事项,再来写sql!

ps:第一次写博客,如有不足的地方欢迎指出!

 

以上是关于存储过程的递归调用(树形结构路径的快速生成)的主要内容,如果未能解决你的问题,请参考以下文章

数据库存储 层次树形结构 的标准做法

「SQL归纳」树形结构表的存储与查询功能的实现——通过路径方法(非递归)

java 递归数据库生成 树形结构问题

java中树形结构怎么实现

Python树形打印目录结构

递归生成树形结构