MySQL父母 - >子查询

时间:2009-06-03 07:34:30

标签: php mysql hierarchical-data

我正在使用mySQL,而且我需要从一个表中选择与父级中任何级别的ID匹配的数据 - >另一个表中的子数据层次结构。

此外,我想用一个编写良好的SQL查询来解决这个问题,而不是我的PHP代码中的递归函数,因为这个功能会被使用很多。

我确实尝试过搜索,我偶然发现了许多类似的问题(大多数问题都得到了解决),但是他们都没有帮助我。

为了帮助说明这种情况,这是我当前的设置

表“文章”:

  • 的article_id
  • CATEGORY_ID
  • ...

表类别

  • CATEGORY_ID
  • PARENT_ID
  • ...

我需要选择“articles.category_id”所在的“文章”中的所有文章,比方说,10。但是还要从“categories.category_id”10所属的树中收到所有类别的所有文章。< / p>

意思是,“10”是父母及其所有孩子,其中10岁是孩子及其所有父母。

没有递归的php函数可能吗?

谢谢。

4 个答案:

答案 0 :(得分:3)

使用您正在使用的Adjacency List设计,无法在一个查询中获取整个树,因为您使用的是MySQL。

其他一些品牌的数据库支持SQL扩展来处理这种设计。 Oracle,Microsoft SQL Server,IBM DB2和PostgreSQL 8.4(目前处于测试阶段)支持SQL扩展。

存在其他数据库设计,允许您更有效地查询树。这个问题已经在StackOverflow,博客和文章中多次得到解决。

你也可以阅读Joe Celko的“Trees and Hierarchies in SQL for Smarties”,深入研究了几个这样的设计。

答案 1 :(得分:2)

这可以在MySQL中进行,但需要花费一点力气。你必须写一个这样的函数:

CREATE FUNCTION hierarchy_connect_by_parent_eq_prior_id(value INT) RETURNS INT
NOT DETERMINISTIC
READS SQL DATA
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(id)
                INTO    @id
                FROM    categories
                WHERE   parent = _parent
                        AND id > _id;
                IF @id IS NOT NULL OR _parent = @start_with THEN
                        SET @level = @level + 1;
                        RETURN @id;
                END IF;
                SET @level := @level - 1;
                SELECT  id, parent
                INTO    _id, _parent
                FROM    categories
                WHERE   id = _parent;
        END LOOP;
END

并在查询中使用它:

SELECT  id, parent, level
FROM    (
        SELECT  hierarchy_connect_by_parent_eq_prior_id(id) AS id, @level AS level
        FROM    (
                SELECT  @start_with := 0,
                        @id := @start_with,
                        @level := 0
                ) vars, categories 
        WHERE   @id IS NOT NULL
        ) ho
JOIN    categories hi
ON      hi.id = ho.id

有关详细信息,请参阅我的博客中的此条目:

答案 2 :(得分:1)

在关系数据库中存储分层数据的最常见模式是相邻列表或modified preorder (aka nested set)。另一种方法是使用物化路径,它基本上是一种缓存机制,位于相邻列表的顶部。另请参阅this table for a comparison of pros and cons

答案 3 :(得分:0)

我不知道这对你有多大帮助,但我写了一个小函数,它使用一个MySQL查询生成一个分层树。基本上,所有重要的逻辑都转移到了PHP中。我的解决方案使用邻接列表模型,然后使用PHP引用,以便通过平面建立树数据结构。看看下面的要点,看看你是否有一些灵感。我会帮助你更多,但在我的工作中我必须面对一些问题。

http://gist.github.com/104357