具有多个级别的多个关系父/子

时间:2017-05-10 12:33:59

标签: mysql sql performance relational-database relationships

我有一个名为companies的MySQL表,如下所示:

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

每家公司可能有多个父母(例如:comp3,这是comp2comp6的孩子),每个父母可能有多个孩子,每个孩子可以是父母本身多个孩子等等......所以,它可以有无限级别(关系)。

我研究了几种解决方案(http://www.codeproject.com/Articles/818694/SQL-queries-to-manage-hierarchical-or-parent-childhttp://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/),但我不认为它适合我的问题,因为同一家公司(基于id_comp列)可以有多个父母。

我有两个问题:

  1. 如果我有成千上万的关系(可扩展),这是正确的方法吗?
  2. 如果name(这是唯一的,基于id_comp)查询选择其兄弟(相同的parent_id),其直接父母及其直接子(s),我该如何? )。

2 个答案:

答案 0 :(得分:1)

如果您需要处理分层数据(将所有祖先/后代变得棘手),Mysql不是最佳选择。但是,如果你关心的只是找到直接的父母/孩子,你的表应该没问题(虽然我可能会将其分解为单独的Company和CompanyParent表,以便不多次输入公司名称。)

这会给你兄弟们:

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;

这会给你直接的父母:

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;

这会给你直接的孩子:

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;

答案 1 :(得分:1)

你有一个简单的&#34;很多:很多&#34;关系。但是,由于没有循环,您有一个与实际不相关(也不可检查)的限制。

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根据定义为UNIQUEINDEX,因此可以防止重复关系(1仅为2的父级一次)并提供有效的方法来横穿一个方向。

必要时使用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 != @me;

我(直系)父母:

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;

我的(直系)孩子:

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;
阿姨,叔叔,第一堂兄弟会有点麻烦。所有的祖先或后代都会变得更加混乱,应该通过应用程序代码或存储过程中的循环来完成。