跳到主要内容

JOINs

JOIN 用于将两个表中的行组合起来,创建一个新的组合行,以便在查询(Query)中使用。

简介

当数据分散在多个相关表中时,JOIN 非常有用。例如,一个表存储员工信息,另一个表存储部门详情。

我们来看一下示例数据:

员工表(Employees Table):

SELECT * FROM employees ORDER BY id;
idnamedepartmentsalary
1AliceEngineering75000.00
2BobEngineering80000.00
3CarolMarketing65000.00
4DavidSales70000.00
5EveMarketing68000.00

部门表(Departments Table):

SELECT * FROM departments ORDER BY id;
idnamebudget
1Engineering1000000.00
2Marketing500000.00
3Sales750000.00

这两个表有一个共同的关系:employees.departmentdepartments.name 匹配。JOIN 让我们能够组合这些相关数据。

JOIN 的类型

内连接(INNER JOIN)

内连接(INNER JOIN)将一个表中的每一行与另一个表中的匹配行配对。

-- 获取员工及其部门预算
SELECT e.name, e.salary, d.name as department_name, d.budget
FROM employees e
INNER JOIN departments d ON e.department = d.name
ORDER BY e.name;

输出:

namesalarydepartment_namebudget
Alice75000.00Engineering1000000.00
Bob80000.00Engineering1000000.00
Carol65000.00Marketing500000.00
David70000.00Sales750000.00
Eve68000.00Marketing500000.00

输出仅包含 employees.departmentdepartments.name 之间存在匹配的行。

左连接(LEFT JOIN)

左连接(LEFT JOIN)返回左表中的所有行,以及右表中匹配的数据。如果没有匹配项,右表的列将包含 NULL。

-- 获取所有员工,并显示其部门预算(如果可用)
SELECT e.name, e.department, d.budget
FROM employees e
LEFT JOIN departments d ON e.department = d.name
ORDER BY e.name;

输出:

namedepartmentbudget
AliceEngineering1000000.00
BobEngineering1000000.00
CarolMarketing500000.00
DavidSales750000.00
EveMarketing500000.00

所有员工都会显示,即使他们所在的部门不存在(此时预算将为 NULL)。

右连接(RIGHT JOIN)

右连接(RIGHT JOIN)返回右表中的所有行,以及左表中匹配的数据。

-- 获取所有部门,并显示其中的员工(如果有)
SELECT d.name as department_name, e.name as employee_name
FROM employees e
RIGHT JOIN departments d ON e.department = d.name
ORDER BY d.name, e.name;

输出:

department_nameemployee_name
EngineeringAlice
EngineeringBob
MarketingCarol
MarketingEve
SalesDavid

所有部门都会显示,即使部门中没有员工(此时 employee_name 将为 NULL)。

全连接(FULL JOIN)

全连接(FULL JOIN)返回两个表中的所有行,并在可能的情况下进行匹配。

-- 获取所有员工和所有部门
SELECT e.name as employee_name, d.name as department_name
FROM employees e
FULL JOIN departments d ON e.department = d.name
ORDER BY e.name, d.name;

输出:

employee_namedepartment_name
AliceEngineering
BobEngineering
CarolMarketing
DavidSales
EveMarketing

显示所有员工和部门,没有匹配项的地方为 NULL。

交叉连接(CROSS JOIN)

交叉连接(CROSS JOIN)会创建一个笛卡尔积(Cartesian product)——第一个表中的每一行都与第二个表中的每一行组合。

警告:这可能会产生非常大的结果集。请谨慎使用。

-- 每个员工与每个部门配对(很少使用)
SELECT e.name, d.name as department
FROM employees e
CROSS JOIN departments d
ORDER BY e.name, d.name;

输出(部分 - 总共 15 行):

namedepartment
AliceEngineering
AliceMarketing
AliceSales
BobEngineering
BobMarketing
BobSales
CarolEngineering
......

结果:5 名员工 × 3 个部门 = 总共 15 行。

JOIN 的实现

使用 ON 子句(推荐)

SELECT e.name, d.budget
FROM employees e
JOIN departments d ON e.department = d.name;

使用 WHERE 子句(旧式)

SELECT e.name, d.budget
FROM employees e, departments d
WHERE e.department = d.name;

建议:使用 ON 子句语法,因为它更清晰,并且能正确处理外连接。

多表 JOIN

你可以将多个 JOIN 链接在一起,以组合来自两个以上表的数据:

-- 获取员工、部门预算和项目信息(如果存在 projects 表)
SELECT e.name, d.name as department, d.budget
FROM employees e
JOIN departments d ON e.department = d.name
JOIN projects p ON d.id = p.department_id
WHERE p.status = 'Active';

何时使用各种 JOIN 类型

  • 内连接(INNER JOIN):当你只需要两个表中都匹配的记录时。
  • 左连接(LEFT JOIN):当你需要左表中的所有记录,并尽可能匹配右表时。
  • 右连接(RIGHT JOIN):当你需要右表中的所有记录,并尽可能匹配左表时。
  • 全连接(FULL JOIN):当你需要两个表中的所有记录时。
  • 交叉连接(CROSS JOIN):很少使用;仅在明确需要笛卡尔积(Cartesian product)时使用。