SQL JOIN 全解析:用 `users` 与 `orders` 表彻底掌握内连接、左连接、右连接
SQL JOIN 全解析:用 users
与 orders
表彻底掌握内连接、左连接、右连接
在日常开发中,SQL 的连接(JOIN)语句是数据库查询的核心技能。尤其在多表联合查询时,不掌握好 INNER JOIN
、LEFT JOIN
、RIGHT JOIN
,你就很容易写出“行数膨胀”、数据丢失、NULL
满天飞的奇怪结果。
本文将用两张简单的表 users
(用户)和 orders
(订单)作为例子,深入讲解三种常见的连接方式。
一、准备工作:建表与数据
我们先创建两张表并插入一些测试数据。
表结构:
-- 用户表:左表
CREATE TABLE users (id INT PRIMARY KEY,name VARCHAR(50)
);-- 订单表:右表
CREATE TABLE orders (id INT PRIMARY KEY,user_id INT,item VARCHAR(100),FOREIGN KEY (user_id) REFERENCES users(id)
);
示例数据:
-- 插入用户数据
INSERT INTO users (id, name) VALUES
(1, '孙悟空'),
(2, '苏有朋'),
(3, '李白'),
(4, '赵云'),
(5, '诸葛亮');-- 插入订单数据
INSERT INTO orders (id, user_id, item) VALUES
(101, 1, '金箍棒'),
(102, 2, '琵琶'),
(103, 1, '筋斗云'),
(104, 99, '无主之剑'); -- 注意:user_id=99 不存在于 users 中
二、INNER JOIN:内连接
SELECT a.id, a.name, b.item
FROM users a
INNER JOIN orders b ON a.id = b.user_id;
结果:
id | name | item |
---|---|---|
1 | 孙悟空 | 金箍棒 |
2 | 苏有朋 | 琵琶 |
1 | 孙悟空 | 筋斗云 |
特点:
- 只保留能成功匹配的记录。
user_id=99
的订单匹配不到 → 被排除。李白
、赵云
、诸葛亮
没下单 → 被排除。孙悟空
有两个订单 → 出现两次。
总结一句话:
内连接 = 两边都有才要。
三、LEFT JOIN:左连接
SELECT a.id, a.name, b.item
FROM users a
LEFT JOIN orders b ON a.id = b.user_id;
结果:
id | name | item |
---|---|---|
1 | 孙悟空 | 金箍棒 |
1 | 孙悟空 | 筋斗云 |
2 | 苏有朋 | 琵琶 |
3 | 李白 | NULL |
4 | 赵云 | NULL |
5 | 诸葛亮 | NULL |
特点:
- 保留所有左表(users)数据。
- 匹配不到的订单信息 → 填充为
NULL
。 user_id=99
的订单仍然被丢弃。
总结一句话:
左连接 = 左边全保,右边能连就连,不能连就补 NULL。
四、RIGHT JOIN:右连接
SELECT a.id, a.name, b.item
FROM users a
RIGHT JOIN orders b ON a.id = b.user_id;
结果:
id | name | item |
---|---|---|
1 | 孙悟空 | 金箍棒 |
1 | 孙悟空 | 筋斗云 |
2 | 苏有朋 | 琵琶 |
NULL | NULL | 无主之剑 |
特点:
- 保留所有右表(orders)数据。
- 匹配不到的用户信息 → 补
NULL
。 user_id=99
没用户匹配 → 仍然出现在结果中。
总结一句话:
右连接 = 右边全保,左边对不上就补 NULL。
五、膨胀现象:JOIN 会让行数增加吗?
是的!比如:
SELECT a.*, b.*
FROM users a
LEFT JOIN orders b ON a.id = b.user_id;
你可能以为每个用户只出现一行,结果 孙悟空
出现了两次。
原因:
JOIN
会对满足条件的所有组合都生成结果。孙悟空
有两个订单 → 出现两行。赵云
没下单 → 也会保留一行(item=NULL
)。
小贴士:
连接时不是“找一个就停”,而是“所有匹配的都拿出来”。
六、常见场景推荐
场景 | 推荐 JOIN |
---|---|
只看有订单的用户 | INNER JOIN |
列出所有用户 + 他们的订单情况 | LEFT JOIN |
列出所有订单 + 是否找到下单用户 | RIGHT JOIN |
查出哪些用户没有下单 | LEFT JOIN + WHERE b.id IS NULL |
示例:
SELECT a.id, a.name
FROM users a
LEFT JOIN orders b ON a.id = b.user_id
WHERE b.id IS NULL;
结语
- JOIN 本质上是“表之间的行配对”,不只是挑字段而已。
- 行数会膨胀,尤其是一对多、多对多连接时尤为明显。
- 熟练掌握 JOIN,才能写出既高效又准确的 SQL 查询。
一图了解JOIN
参考链接
-
SQL Joins Visualizer
一目了然地展示各种 JOIN 类型行为。 -
LeetCode SQL Tutorial(JOIN 练习)
通过实战题目巩固 JOIN 和子查询等知识点。 -
W3Schools:SQL JOIN
基础入门首选,配有图解和在线练习。 -
MySQL JOIN 语法官方文档
官方介绍各种 JOIN 的语法规则和性能提示。 -
PostgreSQL JOIN Types
PostgreSQL 对 JOIN 的详细描述,适用于所有标准 SQL 数据库。 -
Join Data In SQL