如何在 MySQL 中的两个表之间进行两次连接,使它们相互链接?

How to make two joins between two tables in MySQL such that they are interlinked to each other?

我在一个名为 employeebranch 的公司数据库中有两个 table,每个都有一个外键。 employee table 看起来像这样:

+------------+-------------+------+-----+---------+----------------+
| Field      | Type        | Null | Key | Default | Extra          |
+------------+-------------+------+-----+---------+----------------+
| emp_id     | int         | NO   | PRI | NULL    | auto_increment |
| first_name | varchar(30) | YES  |     | NULL    |                |
| last_name  | varchar(30) | YES  |     | NULL    |                |
| birth_date | date        | YES  |     | NULL    |                |
| sex        | varchar(1)  | YES  |     | NULL    |                |
| salary     | int         | YES  |     | NULL    |                |
| super_id   | int         | YES  | MUL | NULL    |                |
| branch_id  | int         | YES  | MUL | NULL    |                |
+------------+-------------+------+-----+---------+----------------+

分支 table 看起来像这样:

+----------------+-------------+------+-----+---------+-------+
| Field          | Type        | Null | Key | Default | Extra |
+----------------+-------------+------+-----+---------+-------+
| branch_id      | int         | NO   | PRI | NULL    |       |
| branch_name    | varchar(30) | YES  |     | NULL    |       |
| mgr_id         | int         | YES  | MUL | NULL    |       |
| mgr_start_date | date        | YES  |     | NULL    |       |
+----------------+-------------+------+-----+---------+-------+

在员工 table 中,branch_id 外键引用 branch table 的 branch_id。在分支 table 中,manager_id 外键引用 employee table.

employee_id

我将以 循环方式 (非正式地说)在这两个 table 之间形成两个连接,这样 employee.branch_id 与 [=24 形成一个连接=],这样 branch.manager_idemployee.employee_id.

形成一个连接

所以我想要将这两个连接连接到 return 的查询是:

employee.first_name AS employee_name, employee.branch_id, branch.branch_name, branch.manager_id, employee.employee_id AS manager_name

我想不出一个可能的解决方案来解决这个问题,因为每个连接中的 LEFT table 是不同的,我不知道如何定义多个 LEFT table每个加入一个 SQL 查询。

数据库管理系统:MySQL v8.0.26

P.S:我的问题与 this question 不同,因为在上述问题中,两个连接的 LEFT table 是相同的,在我的例子中,它不是.

如何着手解决

可以使用 Table 别名在两列之间形成两个连接。正如问题所指出的,employeebranch table 之间要形成一个连接,而 branch 和 [= 之间需要形成另一个连接13=] table。这些类型的连接中有点棘手的部分是在连接两个 table 的 ON 关键字之后指定的关系。

正如@philipxy 在对此问题的评论中所写:

Constraints (including FKs & PKs) need not hold, be declared or be known in order to record or query. Joins are binary, the left table is the result of any previous joins in a series without parentheses. Except for output column order, inner & cross joins have no direction, t join u on c is u join t on c.

所以根据评论,我们将在 employeebranch 之间形成一个连接,在 employee 和分支 table 的别名 [=] 之间形成另一个连接21=]。这里常见的混淆是大多数人(包括我之前)认为连接有一个“方向”,philipxy 在他的上述评论中涵盖了这一点。

问题的解决方法

您可以编写一个 SQL 查询,从 employee table 和 branch_name 来自 branch table 并在 branch_id 的基础上形成两个 table 之间的连接。您必须从名为 branch2 的分支 table 的别名中查询 mgr_id;你必须从员工table查询分支经理的first_namelast_name。您可以在 emp_id 的基础上轻松加入员工和分支机构 table 这样 mgr_id=emp_id.

您终于可以像这样编写 SQL 问题查询:

SELECT employee.first_name, employee.last_name, employee.branch_id,
branch.branch_name,
branch2.mgr_id, employee.first_name AS manager_first_name, employee.last_name AS manager_last_name
FROM employee
JOIN branch ON employee.branch_id=branch.branch_id
JOIN branch branch2 ON branch2.mgr_id=employee.emp_id;

额外信息

上面提到的查询会 return 这个:

+------------+-----------+-----------+-------------+--------+--------------------+-------------------+
| first_name | last_name | branch_id | branch_name | mgr_id | manager_first_name | manager_last_name |
+------------+-----------+-----------+-------------+--------+--------------------+-------------------+
| David      | Wallace   |         1 | Corporate   |    100 | David              | Wallace           |
| Michael    | Scott     |         2 | Scranton    |    102 | Michael            | Scott             |
| Josh       | Porter    |         3 | Stamford    |    106 | Josh               | Porter            |
+------------+-----------+-----------+-------------+--------+--------------------+-------------------+

这些结果可能看起来 没用 因为我们在 table 之间形成了一个 INNER JOIN 所以它只是 return 我们的名字作为特定分支机构“经理”的员工。如果你在 table 之间形成 LEFT JOIN 而不是 INNER JOIN 你会得到这样的结果:

+------------+-----------+-----------+-------------+--------+--------------------+-------------------+
| first_name | last_name | branch_id | branch_name | mgr_id | manager_first_name | manager_last_name |
+------------+-----------+-----------+-------------+--------+--------------------+-------------------+
| David      | Wallace   |         1 | Corporate   |    100 | David              | Wallace           |
| Jan        | Levinson  |         1 | Corporate   |   NULL | Jan                | Levinson          |
| Michael    | Scott     |         2 | Scranton    |    102 | Michael            | Scott             |
| Angela     | Martin    |         2 | Scranton    |   NULL | Angela             | Martin            |
| Kelly      | Kapoor    |         2 | Scranton    |   NULL | Kelly              | Kapoor            |
| Stanley    | Hudson    |         2 | Scranton    |   NULL | Stanley            | Hudson            |
| Josh       | Porter    |         3 | Stamford    |    106 | Josh               | Porter            |
| Andy       | Bernard   |         3 | Stamford    |   NULL | Andy               | Bernard           |
| Jim        | Halpert   |         3 | Stamford    |   NULL | Jim                | Halpert           |
+------------+-----------+-----------+-------------+--------+--------------------+-------------------+

这些结果并不像预期的那样,因为不是任何分支机构经理的员工只有 mgr_idNULL 值,而他们所说的分支机构实际上有经理。由于 mgr_id 为 NULL,manager_first_namemanager_last_name 也有意想不到的结果。

发生上述情况是因为我们不能为两名员工配备相同的经理,因为 mgr_id 不能跨行相同,因为 emp_id 是 [=13 的主键=] table.

学分

  • @philpxy 对这个问题的评论