Проверьте, является ли потомок потомком, используя один запрос mysql

Предположим, у меня есть эта таблица

parent | child 
   1       2        
   1       3        
   2       4        
   4       5        
   5       6        

и я хочу проверить, является ли 6 потомком 1 (что есть).... Могу ли я выполнить это в одном запросе, или мне придется неизбежно получить все данные и обработать их с помощью PHP?

3 ответа

Решение

Вы можете пройтись по дереву с помощью рекурсии в MySQL без обработки данных в PHP. MySQL не поддерживает настоящую рекурсию, поэтому вам придется согласиться на некоторые методы рекурсивного преобразования:

Один метод описан в этом вопросе SO, но будет включать изменение ваших таблиц.

Другой метод - использование хранимой функции, которая будет проходить по таблице до тех пор, пока работа не будет выполнена (что в некотором роде рекурсивно). Это, вероятно, будет работать с вашей текущей таблицей, но будет более сложным для достижения.

У меня здесь есть пример, который просматривает таблицу страниц TYPO3 и находит все идентификаторы страниц для данной корневой строки (сравнимо с тем, что вы пытаетесь достичь):

BEGIN
        DECLARE _id INT;
        DECLARE _parent INT;
        DECLARE _next INT;
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET @id = NULL;

        SET _parent = @id;
        SET _id = -1;

        IF @id IS NULL THEN
                RETURN NULL;
        END IF;

        LOOP
                SELECT  MIN(uid)
                INTO    @id
                FROM    pages
                WHERE   pid = _parent
                AND uid > _id
                AND deleted = 0
                AND hidden =0;                
                IF @id IS NOT NULL OR _parent = @start_with THEN
                        SET @level = @level + 1;
                        RETURN @id;
                END IF;
                SET @level := @level - 1;
                SELECT  uid, pid
                INTO    _id, _parent
                FROM    pages
                WHERE   uid = _parent
                AND     deleted = 0
                AND     hidden = 0;
        END LOOP;
END

Извините, что сейчас у меня нет времени адаптировать этот пример к вашим потребностям, что делает этот ответ неполным, но я надеюсь, что, тем не менее, это может привести вас на правильный путь.

Для этого в одном запросе требуется рекурсивный синтаксис, который MySQL не поддерживает. Oracle использует with ... connect by prior и SqlServer использует CTE (Common Table Expressions) для рекурсии.

По сути, вам придется запрашивать и анализировать с помощью PHP или создать временную таблицу, используя хранимую процедуру, чтобы выполнить рекурсию программно.

Это дерево (или график, если у одного узла может быть более одного родителя)... Каждый узел дерева, которому известно только, является родителем, вы не можете проанализировать древовидную структуру в обратном направлении с помощью одного "прыжка".

Или, лучше, вы могли бы, но только если вы сохраните полный путь от узла к корню дерева в строку базы данных узла, как это...

parent | child | path
   1       3      3,1
   3       2      2,3,1

И так далее...

Вы также можете прочитать это: O (1) алгоритм, чтобы определить, является ли узел потомком другого узла в дереве с множеством путей?

Другие вопросы по тегам