Appearance
SQL 四种表连接完全指南
更新: 7/25/2026 字数: 0 字 时长: 0 分钟
一次讲透 内连接 / 左连接 / 右连接 / 全外连接:用统一示例数据、精准语法、真实场景,配合可交互的动画,把「表与表如何匹配」这件事彻底讲清楚。

为什么需要 JOIN
关系型数据库把数据拆分到多张表中以减少冗余(范式化)。当我们需要「跨表」获取完整信息时,就要用 JOIN 把它们按某个关联字段重新拼装起来。
四种连接的本质区别只有一句话:当左右两表在关联字段上匹配不上时,这条记录要不要保留、缺失的一侧用什么填充。
- INNER JOIN:只保留两边都匹配上的。
- LEFT JOIN:保留左表全部,右表缺失补
NULL。 - RIGHT JOIN:保留右表全部,左表缺失补
NULL。 - FULL OUTER JOIN:两边全部保留,缺失一侧补
NULL。
统一示例数据
后续所有示例都基于下面这两张表:users(用户表)与 orders(订单表),通过 users.id = orders.user_id 关联。
sql
-- 用户表
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(20)
);
-- 订单表
CREATE TABLE orders (
order_id INT PRIMARY KEY,
user_id INT, -- 关联 users.id,可能为空
amount DECIMAL(10,2)
);
INSERT INTO users (id, name) VALUES
(1, '张三'),
(2, '李四'),
(3, '王五'),
(4, '赵六'); -- 赵六尚未下过单
INSERT INTO orders (order_id, user_id, amount) VALUES
(101, 1, 200.00),
(102, 1, 150.00),
(103, 2, 300.00),
(104, 5, 500.00); -- user_id=5 是脏数据/游客单,users 表中不存在users 表
| id | name |
|---|---|
| 1 | 张三 |
| 2 | 李四 |
| 3 | 王五 |
| 4 | 赵六 |
orders 表
| order_id | user_id | amount |
|---|---|---|
| 101 | 1 | 200.00 |
| 102 | 1 | 150.00 |
| 103 | 2 | 300.00 |
| 104 | 5 | 500.00 |
记住这两条「边界数据」
- 赵六(id=4):有用户,但没有订单 → 用来考验「左表独有行」。
- 订单 104(user_id=5):有订单,但没有对应用户 → 用来考验「右表独有行」。
正是这两行,决定了四种 JOIN 结果的差异。
动画演示
SQL 四种连接可视化演示
通过用户表与订单表,直观理解 INNER / LEFT / RIGHT / FULL OUTER JOIN 的执行流程与结果差异。
① 示例数据
users(用户表)
| id | name |
|---|---|
| 1 | Alice |
| 2 | Bob |
| 3 | Carol |
| 4 | David |
注:David(id=4) 没有任何订单。
orders(订单表)
| order_id | user_id | amount |
|---|---|---|
| 101 | 1 | 200 |
| 102 | 1 | 350 |
| 103 | 2 | 120 |
| 104 | 3 | 500 |
| 105 | 5 | 800 |
注:订单 #105(user_id=5) 是一条孤儿订单,无对应用户。
② 选择连接类型
③ 内连接 · INNER JOIN
定义
只返回两张表中连接字段能够相互匹配的行。任意一方没有匹配的记录都会被丢弃,因此结果是两表的“交集”。
对应 SQL 语句
SELECT u.id, u.name, o.order_id, o.amount
FROM users u
INNER JOIN orders o
ON u.id = o.user_id;执行流程(逐行匹配)
0 / 5
点击「下一步」或「全部展开」查看逐行匹配过程。
最终结果集 共 4 行
完成上方执行流程后,将在此展示最终结果集。
一、内连接 INNER JOIN
定义
只返回两张表在关联字段上都能匹配上的行。任意一侧匹配不上的记录都会被丢弃,是最常用、也最「严格」的连接。

语法
sql
SELECT 字段列表
FROM 左表 A
INNER JOIN 右表 B
ON A.关联字段 = B.关联字段;
-- INNER 关键字可省略,JOIN 默认即内连接示例 SQL
sql
SELECT u.id, u.name, o.order_id, o.amount
FROM users u
INNER JOIN orders o
ON u.id = o.user_id;结果(赵六无订单被丢弃,订单 104 无用户也被丢弃):
| id | name | order_id | amount |
|---|---|---|---|
| 1 | 张三 | 101 | 200.00 |
| 1 | 张三 | 102 | 150.00 |
| 2 | 李四 | 103 | 300.00 |
适用场景
- 只关心「有明确关联关系」的数据,如查询已下单用户及其订单。
- 统计报表中需要排除孤立数据的场景。
- 多表串联查询(A→B→C 都必须存在)。
动画方案:Mermaid 分步匹配图
下图逐步展示匹配过程——高亮的连线即最终保留的结果:
二、左连接 LEFT JOIN
定义
以左表为主:返回左表的全部行;对每一行,若右表有匹配则拼接,若没有则右表字段全部填 NULL。左表数据「一行都不会少」。

语法
sql
SELECT 字段列表
FROM 左表 A
LEFT JOIN 右表 B -- 亦可写作 LEFT OUTER JOIN
ON A.关联字段 = B.关联字段;示例 SQL
sql
SELECT u.id, u.name, o.order_id, o.amount
FROM users u
LEFT JOIN orders o
ON u.id = o.user_id;结果(赵六被保留,订单字段为 NULL;订单 104 因不属于任何用户被丢弃):
| id | name | order_id | amount |
|---|---|---|---|
| 1 | 张三 | 101 | 200.00 |
| 1 | 张三 | 102 | 150.00 |
| 2 | 李四 | 103 | 300.00 |
| 3 | 王五 | NULL | NULL |
| 4 | 赵六 | NULL | NULL |
适用场景
- 查询所有用户及其订单情况,包括「从未下单」的用户。
- 找出缺失关联的数据:
... LEFT JOIN ... WHERE B.key IS NULL,即可筛出「未下单用户」。 - 主表数据必须完整展示的一切报表(如用户列表页附带统计)。
动画方案:纯 CSS 分步高亮
左表整体以蓝色高亮表示「全部保留」,无匹配行显示 NULL 徽标:
users(左表 · 全部保留)
1 张三 → 101 / 102
2 李四 → 103
3 王五 → NULL
4 赵六 → NULL
orders(右表 · 仅匹配部分参与)
101 · user 1
103 · user 2
104 · user 5(无对应用户,丢弃)
动画原理
每一行用 animation-delay 递增,形成「逐行落位」的分步效果;左列外描边(keep-all)强调「左表整体保留」,null-row 的虚线框直观表达「补 NULL」。刷新页面即可重新播放。
三、右连接 RIGHT JOIN
定义
以右表为主:返回右表的全部行;左表无匹配时左侧字段填 NULL。它与 LEFT JOIN 完全对称——A RIGHT JOIN B 等价于 B LEFT JOIN A。

语法
sql
SELECT 字段列表
FROM 左表 A
RIGHT JOIN 右表 B -- 亦可写作 RIGHT OUTER JOIN
ON A.关联字段 = B.关联字段;示例 SQL
sql
SELECT u.id, u.name, o.order_id, o.amount
FROM users u
RIGHT JOIN orders o
ON u.id = o.user_id;结果(全部订单保留,订单 104 无对应用户,用户字段为 NULL;赵六无订单被丢弃):
| id | name | order_id | amount |
|---|---|---|---|
| 1 | 张三 | 101 | 200.00 |
| 1 | 张三 | 102 | 150.00 |
| 2 | 李四 | 103 | 300.00 |
NULL | NULL | 104 | 500.00 |
适用场景
- 以明细表 / 事实表为主,检查是否存在「找不到主数据」的脏数据(如订单 104)。
- 实践中较少直接使用,通常改写为 LEFT JOIN 以提升可读性——把要保留的表放在
FROM后即可。
动画方案:Mermaid 时序图(强调「右表驱动」)
用时序图表达「以右表每一行为起点,反查左表」的驱动方向:
四、全外连接 FULL OUTER JOIN
定义
两表全部行都保留:匹配上的正常拼接,左表独有行右侧补 NULL,右表独有行左侧补 NULL。相当于 LEFT JOIN 与 RIGHT JOIN 结果的并集。

语法
sql
SELECT 字段列表
FROM 左表 A
FULL OUTER JOIN 右表 B
ON A.关联字段 = B.关联字段;兼容性提醒
MySQL 不支持 FULL OUTER JOIN(PostgreSQL、SQL Server、Oracle 支持)。在 MySQL 中需用 LEFT JOIN + UNION + RIGHT JOIN 模拟,见下方示例。
示例 SQL
sql
-- 标准写法(PostgreSQL / SQL Server / Oracle)
SELECT u.id, u.name, o.order_id, o.amount
FROM users u
FULL OUTER JOIN orders o
ON u.id = o.user_id;
-- MySQL 模拟写法
SELECT u.id, u.name, o.order_id, o.amount
FROM users u LEFT JOIN orders o ON u.id = o.user_id
UNION
SELECT u.id, u.name, o.order_id, o.amount
FROM users u RIGHT JOIN orders o ON u.id = o.user_id;结果(赵六与订单 104 都被保留):
| id | name | order_id | amount |
|---|---|---|---|
| 1 | 张三 | 101 | 200.00 |
| 1 | 张三 | 102 | 150.00 |
| 2 | 李四 | 103 | 300.00 |
| 3 | 王五 | NULL | NULL |
| 4 | 赵六 | NULL | NULL |
NULL | NULL | 104 | 500.00 |
适用场景
- 数据对账 / 差异比对:同时找出「A 有 B 没有」和「B 有 A 没有」的记录。
- 两个数据源合并去重,且都不能丢数据的场景。
- 数据质量巡检:一次性暴露双向的孤立数据。
动画方案:CSS 韦恩图三区高亮
用纯 CSS 绘制两个交叠圆,并让「左独有 → 交集 → 右独有」三个区域依次点亮,直观表达「全部保留」:
左独有
赵六
赵六
右独有
订单104
订单104
交集
张三·李四
张三·李四
三步点亮
venn-left(0.1s) → venn-right(0.5s) → venn-center(0.9s) 依次出现,mix-blend-mode:multiply 让交叠区自然加深,对应「两表全保留、交集拼接」的语义。
对比总结
| 维度 | INNER JOIN | LEFT JOIN | RIGHT JOIN | FULL OUTER JOIN |
|---|---|---|---|---|
| 保留范围 | 仅两表交集 | 左表全部 + 交集 | 右表全部 + 交集 | 两表全部 |
| 左表独有行 | ❌ 丢弃 | ✅ 保留(右补 NULL) | ❌ 丢弃 | ✅ 保留(右补 NULL) |
| 右表独有行 | ❌ 丢弃 | ❌ 丢弃 | ✅ 保留(左补 NULL) | ✅ 保留(左补 NULL) |
| 结果行数(本例) | 3 | 5 | 4 | 6 |
| 典型场景 | 已关联的完整数据 | 主表全展示、找缺失 | 明细表全展示、查脏数据 | 双向对账、合并去重 |
| 数据库支持 | 全部支持 | 全部支持 | 全部支持 | ⚠️ MySQL 不支持,需模拟 |
| 等价改写 | — | B RIGHT JOIN A | B LEFT JOIN A | LEFT ∪ RIGHT |
一句话记忆法:
- 想要「交集」→ INNER
- 想要「以谁为准、谁一行不少」→ 谁在
FROM后就用 LEFT - 想要「谁都不能少」→ FULL OUTER