1

假设我有这张桌子

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

我想检查 6 是否是 1 的后代(它是)....我可以在一个查询中完成此操作,还是我必须不可避免地获取所有数据并使用 PHP 处理它们?

4

3 回答 3

1

那是一棵树(如果一个节点可能有多个父节点,则为图)...树的每个节点都只知道是父节点,您不能用单个“跳”向后解析树结构。

或者更好,你可以,但前提是你将从节点到树根的完整路径保存到节点数据库行中,像这样......

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

等等...

您还可以阅读以下内容:O(1) 算法来确定节点是否是多路树中另一个节点的后代?

于 2012-06-18T21:20:45.740 回答
1

在单个查询中执行此操作需要递归语法,而 mysql 不支持。Oracle 使用with ... connect by prior和 SqlServer 使用 CTE(通用表表达式)进行递归。

本质上,您将不得不使用 PHP 进行查询和解析,或者使用存储过程创建一个临时表来以编程方式进行递归。

于 2012-06-18T21:26:22.770 回答
1

您可以在 MySQL 中使用递归遍历树,而无需在 PHP 中处理数据。MySQL 不支持真正的递归,所以你必须适应一些递归技术:

这个 SO question 中描述了一种方法,但会涉及更改您的表格。

另一种方法是使用存储函数,它将循环遍历表,直到工作完成(这在某种程度上是递归的)。这可能适用于您当前的表,但实现起来更复杂。

我在这里有一个示例,它遍历 TYPO3 页面表,查找给定根行的所有页面 ID(与您要实现的目标相当):

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

对不起,我现在没有时间根据您的需要定制这个例子,这使得这个答案不完整,但我希望这能让您走上正确的轨道。

于 2012-06-18T21:30:55.820 回答