等值连接、自然连接与非等值连接
在关系型数据库中,我们经常需要把分散在多张表中的数据拼接起来进行查询。这时候就需要用到**连接(Join)**操作。
很多初学者容易混淆“等值连接”、“自然连接”和“非等值连接”。今天,我们将通过三个具体的数据表,带你一探究竟!
1. 准备具体数据表
为了直观展示连接前后的变化,我们先准备以下三张表:员工表(Employee)、部门表(Department)和薪资等级表(SalaryGrade)。
表1:Employee(员工表)
| EmpId (员工号) | EmpName (姓名) | DeptId (部门号) | Salary (薪资) |
|---|---|---|---|
| 1 | Alice | D1 | 6000 |
| 2 | Bob | D2 | 8500 |
| 3 | Charlie | D1 | 12000 |
表2:Department(部门表)
| DeptId (部门号) | DeptName (部门名称) |
|---|---|
| D1 | 研发部 |
| D2 | 人事部 |
表3:SalaryGrade(薪资等级表)
| Grade (等级) | MinSalary (最低薪资) | MaxSalary (最高薪资) |
|---|---|---|
| 初级 | 0 | 7000 |
| 中级 | 7001 | 10000 |
| 高级 | 10001 | 99999 |
2. 等值连接 (Equi-Join)
概念:只要连接条件中的比较运算符为“=”,就是等值连接。它可以是两个表中任意可比的属性,不要求属性同名。并且,结果表中会保留所有参与连接的列,包括重复的列。
查询需求:查询每个员工的详细信息以及他们所在的部门名称。
我们通过比较两张表中的 DeptId 是否相等来进行连接:
SELECT *
FROM Employee
JOIN Department
ON Employee.DeptId = Department.DeptId;
连接后的结果表:
你会发现,结果中有两列 DeptId,分别来自员工表和部门表,它没有做去重处理。
| EmpId (员工号) | EmpName (姓名) | Employee.DeptId | Salary (薪资) | Department.DeptId | DeptName (部门名称) |
|---|---|---|---|---|---|
| 1 | Alice | D1 | 6000 | D1 | 研发部 |
| 2 | Bob | D2 | 8500 | D2 | 人事部 |
| 3 | Charlie | D1 | 12000 | D1 | 研发部 |
3. 自然连接 (Natural Join)
概念:自然连接是等值连接的一种特例。系统会自动寻找两个表中同名的公共属性进行等值比较,并且会在结果集中把重复的属性列去掉,只保留一份。
查询需求:同样是查询员工信息和部门名称。这次我们使用自然连接:
SELECT *
FROM Employee
NATURAL JOIN Department;
连接后的结果表:
由于 Employee 和 Department 有一个同名字段 DeptId,自然连接会自动基于它进行等值匹配。并且,最关键的是结果表中去掉了多余的 DeptId 列,数据看起来更加干净整洁。
| DeptId (部门号) | EmpId (员工号) | EmpName (姓名) | Salary (薪资) | DeptName (部门名称) |
|---|---|---|---|---|
| D1 | 1 | Alice | 6000 | 研发部 |
| D2 | 2 | Bob | 8500 | 人事部 |
| D1 | 3 | Charlie | 12000 | 研发部 |
4. 非等值连接 (Non-Equi-Join)
概念:连接条件不是使用等号(=),而是使用诸如 >, <, >=, <=, !=, BETWEEN...AND... 等运算符的连接操作。它通常用于判断某个值是否落在另一个表的区间范围内。
查询需求:查询每个员工的姓名、具体薪资以及他们对应的薪资等级。 注意,员工表里只有具体薪资,没有等级;等级表里只有薪资范围。我们需要判断员工的薪资落在哪个范围内:
SELECT Employee.EmpName, Employee.Salary, SalaryGrade.Grade
FROM Employee
JOIN SalaryGrade
ON Employee.Salary BETWEEN SalaryGrade.MinSalary AND SalaryGrade.MaxSalary;
连接后的结果表: 这里系统逐行对比,比如 Alice 的 6000 落在 0~7000 之间,所以匹配到“初级”。这就是典型的非等值连接应用场景。
| EmpName (姓名) | Salary (薪资) | Grade (薪资等级) |
|---|---|---|
| Alice | 6000 | 初级 |
| Bob | 8500 | 中级 |
| Charlie | 12000 | 高级 |
总结
| 连接类型 | 连接条件 | 是否保留重复列 | 典型适用场景 |
|---|---|---|---|
| 等值连接 | 使用 = | 保留所有列 | 需要灵活指定连接字段(字段名不同也可),不在乎结果集有重复列。 |
| 自然连接 | 自动匹配同名属性的等值 | 自动去除重复列 | 表设计规范,拥有相同的公共主外键字段,希望结果集清爽无冗余。 |
| 非等值连接 | 使用 >, <, BETWEEN 等 | 保留所有列 | 判断某个数值或日期是否处于另一张表定义的区间/范围内(如薪水评级、年龄段划分)。 |