Mysql sorting Hierarchical data

半城伤御伤魂 提交于 2019-12-05 03:27:04

问题


I have a question and working last week with this and couldnt solve yet.. I can query submenus with join but i cant order it.

I have a table like this

| 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    |
|-------------------------------------------|

I wanna get something like this.

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

Can anybody give me an idea how can handle this? Thank you


回答1:


I have studied http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/ and found a solution for your problem. I guess you already have your solution but for any other who is searching for same solution I am answering here.

My solution will work for relational Tables also as we can't set zero (0) in parent field in relational table. It will be NULL and my solution works perfectly for relational tables also.

The Function

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 ;

Please replace yourTable with your table name and yourField with your field name by which you want to sort your data.

The Query

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

Please replace yourTable with your table name and yourField with your field name which you want to display.

This will produce the result as you required. I tested it and works well.

Here is http://sqlfiddle.com/#!9/9d060d/2 to see it in action.

Thanks.




回答2:


You can't do this with a single query. Just use recursion in your scripting language of choice

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



回答3:


Based on your answer - you want the results in a flat list. In that case I would say that the most efficient way is to make sure that you change your order strategy, you will avoid unnecessary complexity and overhead when selecting items. You would solve the issue if your ordering would be based on the flat list too:

| 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    |
|-------------------------------------------|

Implementing such ordering is not very hard.



来源:https://stackoverflow.com/questions/15852045/mysql-sorting-hierarchical-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!