使用单个 MySQL 查询检查子项是否为后代


check if a child is a descendant using a single mysql query

假设我有这个表

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

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

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

此 SO 问题中描述了一种方法,但涉及更改表。

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

我这里有一个例子,它遍历一个 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

请原谅我现在没有时间根据您的需求定制此示例,使这是一个不完整的答案,但我希望这仍然可以让您走上正确的轨道。

那是一棵树(如果一个节点可以有多个父节点,则是一个图形)...树的每个节点只知道父节点,你不能用一个"跳"向后解析树结构。

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

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

等等...

你也可以读到这个: O(1) 算法来确定节点是否是多路树中另一个节点的后代?

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

本质上,您必须使用 PHP 进行查询和分析,或者使用存储过程创建一个临时表,以编程方式执行递归。