funzioni memorizzate ricorsive in MySQL
-
04-10-2019 - |
Domanda
Sto cercando di fare una funzione che costruisce in modo ricorsivo un percorso per una specifica categoria
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
Quando si tenta di eseguire questa funzione con una categoria che non ha genitori (parent_id = 0) che funziona benissimo ma quando provo una categoria che ha un parent_id> 0 vengo 1424 funzioni e trigger ricorsiva memorizzati non sono ammessi.
Come faccio a risolvere questo? Ho intenzione di ospitare questo codice su un regolare servizio di web hosting che dovrebbe avere almeno MySQL server versione 5.1.
Dopo qualche aiuto da Ike Walker ho fatto un precedure, invece, che funziona bene
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 ;
Ho quindi utilizzare qualcosa di simile a chiamarlo
CALL getPath(72, @temp); SELECT @temp;
Soluzione
MySQL non consente funzioni ricorsive, anche se si imposta max_sp_recursion_depth.
Non permette fino a 255 ricorsione in una procedura se si imposta max_sp_recursion_depth.
Quindi vi consiglio di sostituire la funzione con una procedura, utilizzando una variabile INOUT per la return_path.
Altri suggerimenti
Dal stored procedure nella sua interrogazione, * con l'aiuto di @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 ;
Creare una funzione:
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$$
In seguito, è possibile selezionare:
SELECT category_id, name, getPath(category_id) AS path FROM article_categories ;