Рекурсивные хранимые функции в MySQL
Я пытаюсь создать функцию, которая рекурсивно строит путь для определенной категории
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), она отлично работает, но когда я пытаюсь использовать категорию с родительским_идом > 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;
Ответы
Ответ 1
MySQL не разрешает рекурсивные функции, даже если вы устанавливаете max_sp_recursion_depth.
Это позволяет до 255 рекурсии в ПРОЦЕДУРЕ, если вы устанавливаете max_sp_recursion_depth.
Поэтому я рекомендую вам заменить вашу функцию процедурой, используя переменную INOUT для пути return_.
Ответ 2
Из хранимой процедуры в вашем вопросе * с помощью @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 ;