MySQL Tree 按父子顺序排序 [英] MySQL Tree ordered by parent and child

查看:44
本文介绍了MySQL Tree 按父子顺序排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用此参考在 MYSQL 中显示树结构(http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/),我看到它只适用于同一个表中的 1 个父级.
如果你有另一张桌子要加入,一切都不会顺利.示例:

I'm trying to display a tree structure in MYSQL with this reference (http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/) and I'm seeing that only works with 1 parent in same table.
If you have another table to join with, nothing go well. Example:

餐桌菜单:

+----+--------+-------+
| id |  name  | order |
| 1  | Father |   0   |
| 2  | Father |   1   |
| 3  | Son    |   0   |
| 4  | Child  |   1   |
| 5  | Granson|   2   |
+----+--------+-------+

表关系

+----+---------+-----------+
| id | menu_id | parent_id |
| 1  |    1    |    NULL   |
| 2  |    2    |    NULL   |
| 3  |    3    |     1     |
| 4  |    4    |     3     |
| 5  |    5    |     4     |
+----+---------+-----------+

做选择

SELECT child_menu.*, menu.* FROM menu, relations AS child_menu
WHERE menu.id = child_menu.menu_id
GROUP BY menu_id

我有这个:

+----+--------+-------+
| id |  name  | order |
| 1  | Father |   0   |
| 2  | Father |   1   |
| 3  | Son    |   0   |
| 4  | Child  |   1   |
| 5  | Granson|   2   |
+----+--------+-------+

我试图在同一个 SELECT 中按顺序离开他们的孩子.
从我在示例中看到的情况来看,仅当父项在同一个表中时才有效.
有人能帮我吗?谢谢

I'm trying to leave their children in order in the same SELECT.
From what I see in the examples, only works if the parent is in the same table.
Can someone help me? thank you

预期输出:

+----+--------+-------+
| id |  name  | order |
| 1  | Father |   0   |
| 3  | Son    |   0   |
| 4  | Child  |   1   |
| 5  | Granson|   2   |
| 2  | Father |   1   |
+----+--------+-------+

I.E. Father
       Son
         Child
            Grandson

推荐答案

除了 Mike Hillyer 的博客中显示的方法之外,还有其他方法可以组织分层数据.我喜欢使用一种我称之为传递闭包表或简称闭包表的方法.在此设计中,您将通过层次结构的每条路径都存储为祖先/后代对.

There are other ways to organize hierarchical data besides the methods shown in Mike Hillyer's blog. I like to use a method I call transitive closure table or closure table for short. In this design, you store every path through the hierarchy, as ancestor/descendant pairs.

create table closure (
    ancestor int,
    descendant int,
    length int,
    primary key (ancestor,descendant),
    key (descendant,ancestor)
);
insert into closure values
(1,1,0),
(1,3,1),
(1,4,2),
(1,5,3),
(2,2,0),
(3,3,0),
(3,4,1),
(3,5,2),
(4,4,0),
(4,5,1),
(5,5,0);

请注意,该集合甚至包括长度为零的路径",即菜单项是其自身的父项".

Note that this set includes even the "paths" of length zero, i.e. a menu item is an "parent" of itself.

现在您可以将每个菜单项 m 连接到它的每一个祖先 a 集合,方法是连接到 m 是后缀的路径.从那里,返回到祖先集合中的菜单项 o,您可以访问 order.

Now you can join each menu item m to every its set of ancestors a, by joining to paths where m is the descandant. From there, join back to the menu item o which is in the set of ancestors, and you can access the order.

使用 GROUP_CONCAT() 从祖先链中每个的 order 生成一串面包屑",这将成为一个字符串,您可以通过排序来获得所需的菜单顺序.

Use GROUP_CONCAT() to make a string of "breadcrumbs" from the order of each in the chain of ancestors, and this becomes a string you can sort by to get the menu order you want.

SELECT m.*, GROUP_CONCAT(o.`order` ORDER BY a.length DESC) AS breadcrumbs
FROM menu AS m
INNER JOIN closure AS a ON a.descendant = m.id
INNER JOIN menu AS o ON a.ancestor = o.id
GROUP BY m.id
ORDER BY breadcrumbs;

+----+----------+-------+-------------+
| id | name     | order | breadcrumbs |
+----+----------+-------+-------------+
|  1 | Father1  |     0 | 0           |
|  3 | Son      |     0 | 0,0         |
|  4 | Child    |     1 | 0,0,1       |
|  5 | Grandson |     2 | 0,0,1,2     |
|  2 | Father2  |     1 | 1           |
+----+----------+-------+-------------+

注意面包屑按字符串排序,所以如果你有一些order 2 或3 位数字,你会得到不规则的结果.确保您的 订单 编号都具有相同的位数.

Note that the breadcrumbs sort as a string, so if you have some order numbers with 2 or 3 digits, you will get irregular results. Make sure your order numbers all have the same number of digits.

或者,您可以简单地将面包屑字符串存储在原始菜单表中:

As an alternative, you could simply store the breadcrumbs strings in your original menu table:

ALTER TABLE menu ADD COLUMN breadcrumbs VARCHAR(255);
UPDATE menu SET breadcrumbs = '0,0,1,2' WHERE id = 5;
etc.

然后你可以做一个更简单的查询:

Then you can do a simpler query:

SELECT * FROM menu ORDER BY breadcrumbs;

但是,如果您更改菜单项的顺序,则由您手动重新计算所有受影响的面包屑字符串.

But then it's up to you to manually recalculate all affected breadcrumb strings, if you ever change the order of the menu items.

这篇关于MySQL Tree 按父子顺序排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆