Mysql8.0递归函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql8.0递归函数相关的知识,希望对你有一定的参考价值。

参考技术A 一般比较普遍的就是四种方法:(具体见 SQL Anti-patterns这本书)

因为不支持递归查询,所以mysql官方当时推荐的是第三种方式:Nested Sets。我是用过的,非常难受。现在支持递归查询,我们可以使用第一种。

其实我还用了一种,一列维持顺序,一列维持层级,有空可以把实现写出来看看。

英文好的朋友请移步到这里: Managing Hierarchical Data in MySQL Using the Adjacency List Model ,不好的同学跟我一起来。

直接语句说明:

好,就这些吧。我是姜友华,下次见。

MySQL中的递归存储函数

【中文标题】MySQL中的递归存储函数【英文标题】:Recursive stored functions in MySQL 【发布时间】:2011-04-14 16:53:26 【问题描述】:

我正在尝试创建一个函数来递归地为特定类别构建路径

CREATE FUNCTION getPath(inId INT)
RETURNS TEXT
DETERMINISTIC
BEGIN
    DECLARE return_path TEXT;
    DECLARE return_parent_id INT;
    SELECT CONCAT('/', name) INTO return_path FROM article_categories WHERE id = inId;
    SELECT parent_id INTO return_parent_id FROM article_categories WHERE id = inId;

    IF return_parent_id > 0 THEN
        SELECT CONCAT(getPath(return_parent_id), return_path) INTO return_path;
    END IF;

    RETURN return_path;
END

当我尝试使用没有父 (parent_id = 0) 的类别运行此函数时,它工作正常,但是当我尝试具有 parent_id > 0 的类别时,我得到 1424 递归存储函数和触发器是不允许的。

我该如何解决这个问题?我将将此代码托管在至少应具有 MySQL 服务器版本 5.1 的常规 Web 托管服务上。


在 Ike Walker 的一些帮助下,我做了一个可以正常工作的程序

DROP PROCEDURE IF EXISTS getPath;
DELIMITER //
CREATE PROCEDURE getPath(IN category_id INT UNSIGNED, OUT return_path TEXT)
BEGIN
    DECLARE parent_id INT UNSIGNED;
    DECLARE path_result TEXT;

    SET max_sp_recursion_depth=50;

    SELECT CONCAT('/', ac.name), ac.parent_id INTO return_path, parent_id FROM article_categories AS ac WHERE ac.id = category_id;

    IF parent_id > 0 THEN
        CALL getPath(parent_id, path_result);
        SELECT CONCAT(path_result, return_path) INTO return_path;
    END IF;
END //
DELIMITER ;

然后我用这样的东西来称呼它

CALL getPath(72, @temp); SELECT @temp;

【问题讨论】:

现在我正在使用 MySQL-Server 版本的 Ubuntu 上进行开发:5.1.41-3ubuntu12.6 (Ubuntu) 我发现forums.mysql.com/read.php?98,224107,224638#msg-224638 谈到了 SET max_sp_recursion_depth=N;其中 N 是允许的递归次数。但我仍然得到 1424 Recursive stored functions and triggers are not allowed. 【参考方案1】:

根据您问题中的存储过程,*在 @Ike Walker 的帮助下,

DROP PROCEDURE IF EXISTS getPath;
DELIMITER $$
CREATE PROCEDURE getPath(IN category_id INT UNSIGNED, OUT return_path TEXT)
BEGIN
    DECLARE parent_id INT UNSIGNED;
    DECLARE path_result TEXT;
    SET max_sp_recursion_depth=50;

    SELECT CONCAT('/', ac.name), ac.parent_id INTO return_path, parent_id FROM article_categories AS ac WHERE ac.id = category_id;
    IF parent_id > 0 THEN
        CALL getPath(parent_id, path_result);
        SELECT CONCAT(path_result, return_path) INTO return_path;
    END IF;
END $$
DELIMITER ;

创建一个函数:

DROP FUNCTION IF EXISTS getPath;
CREATE FUNCTION getPath(category_id INT) RETURNS TEXT DETERMINISTIC
BEGIN
    DECLARE res TEXT;
    CALL getPath(category_id, res);
    RETURN res;
END$$

接下来,您可以选择:

SELECT category_id, name, getPath(category_id) AS path FROM article_categories ;

【讨论】:

【参考方案2】:

MySQL 不允许递归函数,即使您设置了 max_sp_recursion_depth。

如果您设置 max_sp_recursion_depth,它确实允许在 PROCEDURE 中进行多达 255 次递归。

所以我建议你用一个过程替换你的函数,为 return_path 使用一个 INOUT 变量。

【讨论】:

感谢整理,我现在做了一个程序来代替: 删除过程如果存在 getPath; DELIMITER // 创建过程 getPath(IN category_id INT UNSIGNED, OUT return_path TEXT) BEGIN DECLARE parent_id INT UNSIGNED;声明路径结果文本; SET max_sp_recursion_depth=50; SELECT CONCAT('/', ac.name) INTO return_path FROM article_categories AS ac WHERE ac.id = category_id;选择 ac.parent_id INTO parent_id FROM article_categories AS ac WHERE ac.id = category_id; IF parent_id > 0 THEN CALL getPath(parent_id, path_result);选择 CONCAT(path_result, return_path) INTO return_path;万一; END // 分隔符 ;

以上是关于Mysql8.0递归函数的主要内容,如果未能解决你的问题,请参考以下文章

mysql8.0版本递归查询

Python 函数进阶-递归函数

递归函数 集合 列表 元组

UE4定义递归函数

递归与内置函数

函数递归