具有多个级别的多重关系 parent/child
Multiple relations parent/child with multiple levels
我有一个名为 companies
的 MySQL table,如下所示:
+---------+-----------+-----------+
| id_comp | comp_name | id_parent |
+---------+-----------+-----------+
| 1 | comp1 | NULL |
| 2 | comp2 | 1 |
| 3 | comp3 | 2 |
| 4 | comp4 | 2 |
| 5 | comp5 | 2 |
| 6 | comp6 | 1 |
| 3 | comp3 | 6 |
| 5 | comp5 | 6 |
| 7 | comp7 | 6 |
| 4 | comp4 | 6 |
| 8 | comp8 | 4 |
+---------+-----------+-----------+
每个公司可能有多个 parent(例如:comp3
,即 comp2
和 comp6
的 child),每个 parent 可能有多个 child,每个 child 可以是多个 child 的 parent 本身,依此类推......所以,它可以有无限的级别(关系).
我研究了几个解决方案 (http://www.codeproject.com/Articles/818694/SQL-queries-to-manage-hierarchical-or-parent-child, http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/),但我认为它不适合我的问题,因为同一家公司(基于 id_comp
列)可以有多个 parent s.
我有两个问题:
- 如果我有数千个关系(可扩展),这是正确的方法吗?
- 如何给定一个
name
(这是唯一的,基于 id_comp
)查询 select 它的兄弟(相同 parent_id),它的直接 parent(s), 及其直接 child(s).
如果您需要处理分层数据,Mysql 不是最佳选择(获取所有 ancestors/descendants 可能很棘手)。但是,如果您只关心找到直接 parents/children,您的 table 应该没问题(尽管我可能会将其分解为单独的 Company 和 CompanyParent table,这样公司名称就不会输入多次)。
这会给各位兄弟:
select name
from companies
where id_parent in (select id_parent from companies where id_comp = @company_id)
and id_comp <> @company_id
group by name;
这会给你直接 parents:
select p.name
from companies p
join companies c on p.id = c.id_parent
where c.id_comp = @company_id
group by c.name;
这会给你直接 children:
select c.name
from companies p
join companies c on p.id = c.id_parent
where p.id_comp = @company_id
group by c.name;
你们的关系很简单"many:many"。但是,您有一个不相关(也不可检查)的限制,因为没有循环。
CREATE TABLE Relations (
id_comp ...,
id_parent ...,
PRIMARY KEY(id_comp, id_parent), -- for reaching "up"
INDEX(id_parent, id_comp) -- for reaching "down"
) ENGINE=InnoDB;
这将扩展到数百万甚至数十亿个关系。由于 PRIMARY KEY
根据定义是 UNIQUE
和 INDEX
,它可以防止重复关系(1
是 2
的 parent 只有一次) 并提供一种有效的方式来遍历一个方向。
必要时使用DISTINCT
代替GROUP BY
。不要使用IN ( SELECT ...)
,它往往很慢。
我的兄弟姐妹:
SELECT DISTINCT their_kids.*
FROM Relations AS me
JOIN Relations AS my_parents ON my_parents.id_comp = me.id_parent
JOIN Relations AS their_kids ON their_kids.id_parent = parents.id_comp
WHERE me.id_comp = @me
AND their_kids.id_comp != @me;
我的(即时)Parents:
SELECT my_parents.*
FROM Relations AS me
JOIN Relations AS my_parents ON my_parents.id_comp = me.id_parent
WHERE me.id_comp = @me;
我的(即时)Children:
SELECT my_kids.*
FROM Relations AS me
JOIN Relations AS my_kids ON my_kids.id_parent = me.id_comp
WHERE me.id_comp = @me;
阿姨、叔叔、表亲会有点乱。所有的祖先或后代都会更加混乱,应该在应用程序代码或存储过程中使用循环来完成。
我有一个名为 companies
的 MySQL table,如下所示:
+---------+-----------+-----------+
| id_comp | comp_name | id_parent |
+---------+-----------+-----------+
| 1 | comp1 | NULL |
| 2 | comp2 | 1 |
| 3 | comp3 | 2 |
| 4 | comp4 | 2 |
| 5 | comp5 | 2 |
| 6 | comp6 | 1 |
| 3 | comp3 | 6 |
| 5 | comp5 | 6 |
| 7 | comp7 | 6 |
| 4 | comp4 | 6 |
| 8 | comp8 | 4 |
+---------+-----------+-----------+
每个公司可能有多个 parent(例如:comp3
,即 comp2
和 comp6
的 child),每个 parent 可能有多个 child,每个 child 可以是多个 child 的 parent 本身,依此类推......所以,它可以有无限的级别(关系).
我研究了几个解决方案 (http://www.codeproject.com/Articles/818694/SQL-queries-to-manage-hierarchical-or-parent-child, http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/),但我认为它不适合我的问题,因为同一家公司(基于 id_comp
列)可以有多个 parent s.
我有两个问题:
- 如果我有数千个关系(可扩展),这是正确的方法吗?
- 如何给定一个
name
(这是唯一的,基于id_comp
)查询 select 它的兄弟(相同 parent_id),它的直接 parent(s), 及其直接 child(s).
Mysql 不是最佳选择(获取所有 ancestors/descendants 可能很棘手)。但是,如果您只关心找到直接 parents/children,您的 table 应该没问题(尽管我可能会将其分解为单独的 Company 和 CompanyParent table,这样公司名称就不会输入多次)。
这会给各位兄弟:
select name
from companies
where id_parent in (select id_parent from companies where id_comp = @company_id)
and id_comp <> @company_id
group by name;
这会给你直接 parents:
select p.name
from companies p
join companies c on p.id = c.id_parent
where c.id_comp = @company_id
group by c.name;
这会给你直接 children:
select c.name
from companies p
join companies c on p.id = c.id_parent
where p.id_comp = @company_id
group by c.name;
你们的关系很简单"many:many"。但是,您有一个不相关(也不可检查)的限制,因为没有循环。
CREATE TABLE Relations (
id_comp ...,
id_parent ...,
PRIMARY KEY(id_comp, id_parent), -- for reaching "up"
INDEX(id_parent, id_comp) -- for reaching "down"
) ENGINE=InnoDB;
这将扩展到数百万甚至数十亿个关系。由于 PRIMARY KEY
根据定义是 UNIQUE
和 INDEX
,它可以防止重复关系(1
是 2
的 parent 只有一次) 并提供一种有效的方式来遍历一个方向。
必要时使用DISTINCT
代替GROUP BY
。不要使用IN ( SELECT ...)
,它往往很慢。
我的兄弟姐妹:
SELECT DISTINCT their_kids.*
FROM Relations AS me
JOIN Relations AS my_parents ON my_parents.id_comp = me.id_parent
JOIN Relations AS their_kids ON their_kids.id_parent = parents.id_comp
WHERE me.id_comp = @me
AND their_kids.id_comp != @me;
我的(即时)Parents:
SELECT my_parents.*
FROM Relations AS me
JOIN Relations AS my_parents ON my_parents.id_comp = me.id_parent
WHERE me.id_comp = @me;
我的(即时)Children:
SELECT my_kids.*
FROM Relations AS me
JOIN Relations AS my_kids ON my_kids.id_parent = me.id_comp
WHERE me.id_comp = @me;
阿姨、叔叔、表亲会有点乱。所有的祖先或后代都会更加混乱,应该在应用程序代码或存储过程中使用循环来完成。