【问题标题】:Multiple relations parent/child with multiple levels具有多个级别的多个关系父/子
【发布时间】:2017-05-10 12:33:58
【问题描述】:

我有一个名为 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)、直接父级和直接子级。李>

【问题讨论】:

  • 您只关心直系父母/子女?你不需要所有的祖先/后代?
  • @Jerrad,直接上下(父母和孩子),还有兄弟们。
  • 你说name 是独一无二的,但我多次看到它,因此不是UNIQUE

标签: mysql sql performance relational-database relationships


【解决方案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;

【讨论】:

  • 非常感谢,我可以在三个查询之间将它与 Union 集成。选兄弟时如何避免重蹈覆辙?
【解决方案2】:

您有一个简单的“多:多”关系。但是,您有一个并不真正相关(也无法检查)的限制,因为没有循环。

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,因此它可以防止重复关系(12 的父级仅一次)并提供了一种遍历一个方向的有效方法。

必要时使用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;

我的(直系)父母:

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;

阿姨,叔叔,堂兄弟会有点混乱。所有祖先或后代都会更加混乱,应该通过应用程序代码中的循环或存储过程来完成。

【讨论】:

  • 这很有意义,我今天会测试一下,我会回复你。谢谢
  • 还有一个问题,你们都没有在回答中包含。三个选择如何通过联合加入?
  • JOIN 就像“和”; UNION 就像“或”。如果你想要孩子和父母,UNION 一起我的两个查询。好的,英语中“和”的含义令人困惑。数学中“和”(“相交”)与“或”的关系非常清楚。
  • @Vishnu - 在 MySQL 中,您可以将值存储在 @variables 中。也许 Postgres 不使用那种语法。与其他供应商相比,每个供应商在 SQL 方面都有很多差异。
  • 好的。关于变量,语法略有不同。无论如何,在 where 子句中出现错误。将其更改为 WHERE me.id_comp = @me.id_comp 但不返回任何结果。有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 2020-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-21
  • 1970-01-01
相关资源
最近更新 更多