mysql5.0自定义存储过程实现递归

本文介绍了MySQL8.0及以上版本的RECURSIVE递归函数在查询树形结构数据中的使用,以及在8.0以下通过自定义存储过程实现的递归查询方法,包括get_tree_recursive和get_tree两个存储过程的详细步骤和示例。
摘要由CSDN通过智能技术生成

一、mysql自带递归函数

mysql8.0以上才有查询树形结构数据的递归函数RECURSIVE,比如需求是查询一张树形结构表的级别名称上下层级关系路径:

WITH RECURSIVE subordinates AS (
  SELECT id, region_name, parent_id, CAST(region_name AS CHAR(200)) AS path
  FROM mr_industry_region
  WHERE parent_id  = -1 and id = 67652
    UNION all 
  SELECT e.id, e.region_name, e.parent_id, CONCAT(s.path, '/', e.region_name)
  FROM mr_industry_region e
  JOIN subordinates s ON e.parent_id = s.id
)
SELECT id, region_name, path
FROM subordinates;

图中红色的部分替换为需要查询的表即可,字段也根据需要替换

核心字段是id,parent_id

region_name则是级别名称字段

subordinates是递归中用到的临时表的别名,可随意替换

以上sql查询的结果如下

可以看到mysql8.0以上借助函数RECURSIVE实现递归查询还是比较简单的

二、自定义存储过程

8.0以下要想完全通过sql实现递归查询,则需要通过存储过程来实现,使用游标实现递归向下查询

实现递归的存储过程如下

CREATE PROCEDURE get_tree_recursive(IN current_id INT, IN inputLevel INT,IN path VARCHAR(255))
BEGIN
    -- 自定义结束标志
    DECLARE done BOOLEAN  DEFAULT FALSE;
    -- 自定义游标赋值变量
    DECLARE currentId INT;
    DECLARE regionName varchar(255);
    DECLARE parentId INT;
    DECLARE curLevel INT;
    -- 自定义游标
    DECLARE cur CURSOR FOR
        SELECT id, region_name, parent_id,level
        FROM mr_industry_region
        WHERE parent_id = current_id and level = inputLevel;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = true;

        -- 创建临时表
    CREATE TEMPORARY TABLE IF NOT EXISTS temp_mr_industry_region
    (
        id        INT PRIMARY KEY,
        region_name   VARCHAR(255),
        parent_id INT,
                path   VARCHAR(255),
        level     INT
    );

    OPEN cur;

    read_loop:
    LOOP
        FETCH cur INTO currentId, regionName, parentId, curLevel;
        IF done THEN
            LEAVE read_loop;
        END IF;
        INSERT INTO temp_mr_industry_region (id, region_name, parent_id, path,level)
        VALUES (currentId, regionName, parentId,concat(path,'/',regionName), curLevel);
        CALL get_tree_recursive(currentId, inputLevel + 1,concat(path,'/',regionName));
    END LOOP;

    CLOSE cur;

END;

这个存储过程get_tree_recursive用于递归地获取一个层次结构的数据,例如树形结构。以下是存储过程的详细步骤:
 

1.声明变量:
done:布尔变量,作为循环结束的标志,默认为FALSE。
currentId,regionName,parentId,curLevel:用于存储游标取出的当前记录的值。

2.定义游标:
cur:对mr_industry_region表中parent_id等于current_id且level等于inputLevel的记录进行遍历。


3.设置异常处理:
当游标没有更多记录时(NOT FOUND),将done设置为TRUE,退出循环。

4.创建临时表:
temp_mr_industry_region:如果不存在,则创建,用于存储递归过程中获取的树节点信息。

5.打开游标:
OPEN cur:开始遍历游标。

6.读取循环:
read_loop:在循环中,从游标中获取数据并插入到临时表中,同时递归调用自身,将当前节点的子节点添加到路径中。

7.递归调用:
对每个找到的节点,调用get_tree_recursive,传入当前节点的ID,增加的层级(inputLevel + 1)以及更新后的路径(当前路径加上当前节点的名称)。

8.关闭游标:
CLOSE cur:完成循环后关闭游标。


通过这个存储过程,可以构建一个以current_id为根节点,inputLevel指定层级的树结构,并存储在临时表temp_mr_industry_region中。

CREATE PROCEDURE get_tree()
BEGIN
    -- 自定义结束标志
    DECLARE done BOOLEAN DEFAULT FALSE;
    -- 自定义游标赋值变量
    DECLARE currentId INT;
    DECLARE regionName varchar(255);
    DECLARE parentId INT;
    DECLARE curLevel INT;
    -- 自定义游标,查询所有首级进行游标循环
    DECLARE cur CURSOR FOR
        SELECT id, region_name, parent_id, level
        FROM mr_industry_region
        WHERE parent_id = -1;-- 自行修改条件


    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = true;
        

    OPEN cur;
    read_loop:
    LOOP
        FETCH cur INTO currentId, regionName, parentId, curLevel;
        IF done THEN
            LEAVE read_loop;
        END IF;
        INSERT INTO temp_mr_industry_region (id, region_name, parent_id,path, level)
        VALUES (currentId, regionName, parentId,regionName, curLevel);
        CALL get_tree_recursive(currentId, curLevel + 1,regionName);
    END LOOP;
    CLOSE cur;
END;

这个存储过程get_tree与之前的get_tree_recursive有所不同,它首先获取所有顶级节点(即parent_id = -1的节点)并开始递归构建树。以下是其详细步骤:

1.声明变量:
同get_tree_recursive,声明了结束标志done和游标变量currentId,regionName,parentId,curLevel。

2.定义游标:
cur:遍历mr_industry_region表中parent_id为-1的所有记录,这些记录代表树的第一层级。

3.设置异常处理:
当游标没有更多记录时,将done设置为TRUE,退出循环。

4.打开游标:
OPEN cur:开始遍历游标。

5.读取循环:
read_loop:在循环中,从游标中获取数据并插入到临时表temp_mr_industry_region中,同时调用get_tree_recursive进行递归。

6.递归调用:
对每个顶级节点,调用get_tree_recursive,传入当前节点的ID,增加的层级(curLevel + 1)以及节点名称(作为路径的初始部分)。

7.关闭游标:
CLOSE cur:完成循环后关闭游标。

这个存储过程首先获取所有顶级节点,然后对每个顶级节点调用递归存储过程get_tree_recursive,从而构建整个树结构。与get_tree_recursive相比,它不需要传入初始层级inputLevel,因为它是从顶层开始的。

接着执行如下语句:

set SESSION max_sp_recursion_depth=20;

call get_tree();

第一句是mysql要求的递归设置层级深度,session是只在当前sql会话窗口有效,全局的则替换为global,同时账号也需要最高权限,set SESSION max_sp_recursion_depth=20; 我这里设置的是20,不设置默认是0,存储过程无法执行。

第二句则是开始调用存储过程

执行完毕后查看临时表temp_mr_industry_region

注意:level字段如果没有,则把两个存储过程和level有关的字段,参数,游标变量等都 删除,重新执行存储过程即可,数据只能生成一次,重复生成报错。

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL 存储过程是一种在 MySQL 数据库中存储并执行 SQL 语句的方法。MySQL 存储过程可以使用递归技术来处理一些需要对同一数据进行多次处理的问题,比如树形结构的遍历、图形结构的遍历等。下面是一个使用 MySQL 存储过程实现递归的示例: 首先,我们需要创建一个表,用于存储树形结构的数据。假设这个表名为 `tree`,包含如下字段: ``` id INT PRIMARY KEY, name VARCHAR(255), parent_id INT ``` 其中,`id` 是节点的唯一标识符,`name` 是节点的名称,`parent_id` 是节点的父节点标识符。如果一个节点没有父节点,则其 `parent_id` 为 NULL。 接下来,我们可以创建一个存储过程,用于从指定的节点开始遍历整个树形结构。这个存储过程包含两个参数:起始节点的 `id` 和当前节点的深度。 ``` CREATE PROCEDURE traverse_tree (IN start_id INT, IN depth INT) BEGIN DECLARE done INT DEFAULT FALSE; DECLARE cur_id INT; DECLARE cur_depth INT; -- 创建一个游标,查询当前节点的所有子节点 DECLARE cur CURSOR FOR SELECT id FROM tree WHERE parent_id = start_id; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; -- 遍历所有子节点 OPEN cur; read_loop: LOOP FETCH cur INTO cur_id; IF done THEN LEAVE read_loop; END IF; -- 处理当前节点 SET cur_depth = depth + 1; SELECT CONCAT(REPEAT(' ', depth), name) FROM tree WHERE id = cur_id; -- 递归处理当前节点的子节点 CALL traverse_tree(cur_id, cur_depth); END LOOP; CLOSE cur; END; ``` 这个存储过程使用游标查询当前节点的所有子节点,并递归调用自己处理子节点。它还使用了一个 `depth` 参数,用于记录当前节点的深度,以便输出时缩进一定的空格。 我们可以调用这个存储过程,从指定的节点开始遍历树形结构。 ``` CALL traverse_tree(1, 0); ``` 其中,`1` 是起始节点的 `id`,`0` 是起始节点的深度(根节点的深度为 0)。这个存储过程将会输出整个树形结构的层次结构。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值