Mysql排序分层数据

时间:2013-04-06 14:21:39

标签: mysql hierarchical

我有一个问题并且在上周与此工作并且无法解决..我可以通过连接查询子菜单但我无法订购它。

我有一张这样的表

| id   |  name           |  parent | order  |    
|-------------------------------------------|
| 1    | menu1           |  0      |   1    |
| 2    | submenu1        |  1      |   2    |
| 3    | submenu2        |  1      |   1    |
| 4    | subsubmenu      |  2      |   1    |
| 5    | subsubsubmenu:) |  4      |   1    |
| 6    | menu2           |  0      |   3    |
| 7    | menu3           |  0      |   2    |
|-------------------------------------------|

我想得到这样的东西。

| - menu1
      | - submenu2
      | - submenu1
              | - subsubmenu
                       | - subsubsubmenu:)
| - menu3
| - menu2

任何人都可以告诉我如何处理这个问题?谢谢

3 个答案:

答案 0 :(得分:1)

我研究过http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/并为您的问题找到了解决方案。我想你已经有了解决方案,但对于其他正在寻找相同解决方案的人我在这里回答。

我的解决方案也适用于关系表,因为我们无法在关系表的父字段中设置零(0)。它将为NULL,我的解决方案也适用于关系表。

功能

DROP FUNCTION IF EXISTS hierarchy_connect_by_parent_eq_prior_id;
DELIMITER $$
CREATE FUNCTION hierarchy_connect_by_parent_eq_prior_id(value INT) RETURNS INTEGER
NOT DETERMINISTIC
READS SQL DATA
BEGIN
    DECLARE _parent INT;
    DECLARE _rank INT;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET @id = NULL;

    SET _parent = @id;
    SET _rank = 0;

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

    LOOP
        SET @innerrank = 0;
        SELECT p.id 
        INTO   @id
        FROM   (
                SELECT   id, @innerrank := @innerrank+1 AS rank 
                FROM     yourTable 
                WHERE    COALESCE(parent, 0) = _parent 
                ORDER BY yourField
                ) p 
        WHERE   p.rank > _rank LIMIT 0, 1;
        IF @id IS NOT NULL OR _parent = @start_with THEN
                SET @level = @level + 1;
                RETURN @id;
        END IF;
        SET @level := @level - 1;
        SET @innerrank = 0;
        SELECT COALESCE(p.parent, 0), p.rank
        INTO   _parent, _rank
        FROM   (
                SELECT id, parent, @innerrank := @innerrank+1 AS rank
                FROM    yourTable
                WHERE   COALESCE(parent, 0) = (
                    SELECT COALESCE(parent, 0) FROM yourTable WHERE id = _parent
                    ) 
                ORDER BY yourField
               ) p
        WHERE p.id = _parent;
    END LOOP;       
END;
$$
DELIMITER ;

请将yourTable替换为您的表名,将yourField替换为您要对其进行数据排序的字段名称。

查询

SELECT ou.* FROM (
    SELECT hi.id, parent, yourField 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, yourTable 
            WHERE @id IS NOT NULL
        ) ho 
    JOIN yourTable hi ON hi.id = ho.id
) ou

请将yourTable替换为您的表名,将yourField替换为您要显示的字段名称。

这将根据您的要求生成结果。我测试了它并且运行良好。

以下http://sqlfiddle.com/#!9/9d060d/2可以看到它的实际效果。

感谢。

答案 1 :(得分:0)

您无法通过单个查询执行此操作。只需在您选择的脚本语言中使用递归

class Hierarchy

    function __construct(db)
        db = db.connect
        this.stmt = db.prepare "SELECT name FROM Hierarchy WHERE parent = ?"
        this.tree = {}
    end

    function getHierarchyFromParent(parent = 0, tree = null)
        tree = this.tree if tree is null
        while result = this.stmt.execute(parent).fetch
            tree[result.name] = {
                children: this.getHierarchyFromParent result.id tree[result.name]
            }
        end
    end
end

答案 2 :(得分:0)

根据您的回答 - 您希望将结果放在一个平面列表中。在这种情况下,我会说最有效的方法是确保您更改订单策略,在选择项目时将避免不必要的复杂性和开销。 如果您的订购也基于单位清单,您可以解决问题:

| id   |  name           |  parent | order  |    
|-------------------------------------------|
| 1    | menu1           |  0      |   1    |
| 2    | submenu1        |  1      |   2    |
| 3    | submenu2        |  1      |   3    |
| 4    | subsubmenu      |  2      |   4    |
| 5    | subsubsubmenu:) |  4      |   5    |
| 6    | menu2           |  0      |   6    |
| 7    | menu3           |  0      |   7    |
|-------------------------------------------|

实施这样的排序并不是很难。