如何在 MySQL 中的两个表之间进行两次连接,使它们相互链接?
How to make two joins between two tables in MySQL such that they are interlinked to each other?
我在一个名为 employee
和 branch
的公司数据库中有两个 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_id
与 employee.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 别名在两列之间形成两个连接。正如问题所指出的,employee
和 branch
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.
所以根据评论,我们将在 employee
和 branch
之间形成一个连接,在 employee
和分支 table 的别名 [=] 之间形成另一个连接21=]。这里常见的混淆是大多数人(包括我之前)认为连接有一个“方向”,philipxy 在他的上述评论中涵盖了这一点。
问题的解决方法
您可以编写一个 SQL 查询,从 employee
table 和 branch_name
来自 branch
table 并在 branch_id
的基础上形成两个 table 之间的连接。您必须从名为 branch2
的分支 table 的别名中查询 mgr_id
;你必须从员工table查询分支经理的first_name
和last_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_id
和 NULL
值,而他们所说的分支机构实际上有经理。由于 mgr_id
为 NULL,manager_first_name
和 manager_last_name
也有意想不到的结果。
发生上述情况是因为我们不能为两名员工配备相同的经理,因为 mgr_id
不能跨行相同,因为 emp_id
是 [=13 的主键=] table.
学分
- @philpxy 对这个问题的评论
我在一个名为 employee
和 branch
的公司数据库中有两个 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_id
与 employee.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 别名在两列之间形成两个连接。正如问题所指出的,employee
和 branch
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.
所以根据评论,我们将在 employee
和 branch
之间形成一个连接,在 employee
和分支 table 的别名 [=] 之间形成另一个连接21=]。这里常见的混淆是大多数人(包括我之前)认为连接有一个“方向”,philipxy 在他的上述评论中涵盖了这一点。
问题的解决方法
您可以编写一个 SQL 查询,从 employee
table 和 branch_name
来自 branch
table 并在 branch_id
的基础上形成两个 table 之间的连接。您必须从名为 branch2
的分支 table 的别名中查询 mgr_id
;你必须从员工table查询分支经理的first_name
和last_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_id
和 NULL
值,而他们所说的分支机构实际上有经理。由于 mgr_id
为 NULL,manager_first_name
和 manager_last_name
也有意想不到的结果。
发生上述情况是因为我们不能为两名员工配备相同的经理,因为 mgr_id
不能跨行相同,因为 emp_id
是 [=13 的主键=] table.
学分
- @philpxy 对这个问题的评论