Рекурсивные хранимые функции в MySQL - PullRequest
6 голосов
/ 20 сентября 2010

Я пытаюсь создать функцию, которая рекурсивно создает путь для определенной категории

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.


После некоторой помощи от 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;

Ответы [ 2 ]

7 голосов
/ 20 сентября 2010

MySQL не допускает рекурсивные ФУНКЦИИ, даже если вы задаете max_sp_recursion_depth.

Он допускает до 255 рекурсий в ПРОЦЕДУРЕ, если вы устанавливаете max_sp_recursion_depth.

Поэтому я рекомендую вам заменитьфункция с процедурой, используя переменную INOUT для return_path.

3 голосов
/ 11 марта 2017

Из хранимой процедуры в вашем вопросе * с помощью @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 ;
...