我在后台看到有人搜"SQL 8 种 JOIN",转头又看到隔壁热搜挂着"为什么大厂不建议使用多表join",这俩问题放在一起看特别有意思——一边是新手恨不得把所有表都连起来学,一边是老人看到多表 JOIN 就皱眉头。两条热搜问的其实是同一个东西:JOIN 这个东西,到底该怎么用?
先把结论放前面:SQL 里常见的 JOIN 一共有 8 种(有的教材把其中两种归成一类,但主流口径就是 8 种),其中 6 种是日常真正会碰到的,今天我用一套固定数据把它们全部可视化讲明白,顺便把 left join right join 的经典案例一次讲透。至于大厂为什么不建议多表 JOIN,那是 JOIN 用多了之后的代价问题,等你把我下面几张结果图看完,自然就懂了。这篇文章适合刚学 SQL 的小白,也适合写了多年 SQL 但一直凭感觉写 JOIN 的朋友——凭感觉写 JOIN 的人,十个里有八个会踩到后面的坑。
1. 别急着背语法:JOIN 到底在干什么
先别管关键字怎么写。JOIN 本质上干的事非常朴素:把两张表按某个共同字段"拼"在一起。
为什么要拼?因为关系型数据库从一开始就鼓励你"拆表"。你想想,学校如果要记每个学生的成绩,最省事的设计是什么?直接把考试科目、分数全塞进学生信息表,一个学生一行,每行塞几十个字段,行不行?行,但后面你会疯掉:今天加一门科目要改表结构,明天某个学生缺考要填 NULL,后天想查"哪个班数学平均分最高",得把一堆字符串拆来拆去。所以正规设计一定是拆成多张表,考试分数单独放一张成绩表,学生信息单独放一张学生表,中间靠"学号"这个共同字段互相引路。
这个"共同字段"就是 JOIN 的抓手,术语叫连接键(join key)。你现在手上两张表,一张记学生,一张记分数,想知道"小明数学考了多少",光看任何一张表都不行,必须把两张表沿着"学号"这条线拼起来再看。JOIN 干的就是这个缝合工作,跟拼乐高一样:每块积木上都有对应的凸起和凹槽,对准了按下去,一块就拼上了。
打个更生活化的比方:你现在有两份名单,A 名单写着学号和姓名,B 名单写着学号和考试科目。JOIN 就是"按学号把两行捏成一行"的操作。B 名单里如果有人的学号在 A 名单里找不到,那这人要么是转学生信息没录,要么就是来蹭考的;A 名单里如果有学生的学号在 B 名单里没有,那这人就是这次考试缺考了。你到底想让哪些人出现在结果里,这就衍生出了不同类型的 JOIN。所以你会发现,JOIN 的每种类型,本质上都是在回答同一个问题:左右两边对不上的行,我要不要留?
这问题想明白了,后面 8 种 JOIN 就是给你 8 种答案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 六个核心 JOIN 的超直观图解
为了避免空谈,我先固定两张演示表,后面所有 JOIN 都用同一份数据跑,你对照着看会非常清楚。
左表:students(学生表)
| 学号 | 姓名 | 班级 |
|---|---|---|
| 1 | 小明 | 一班 |
| 2 | 小红 | 一班 |
| 3 | 小刚 | 二班 |
| 4 | 小丽 | 三班 |
右表:scores(成绩表)
| 学号 | 科目 | 分数 |
|---|---|---|
| 1 | 数学 | 90 |
| 1 | 语文 | 85 |
| 2 | 数学 | 78 |
| 4 | 数学 | 95 |
| 9 | 英语 | 60 |
注意我故意埋了两个雷:学生表里有个"小刚"(学号3)在成绩表里一条也没有;成绩表里有个学号9的成绩,在学生表里查无此人。这两个雷就是理解各种 JOIN 的关键道具。
2.1 INNER JOIN:两边都能对上的,才留下
INNER JOIN(内连接)的规则最简单:只保留左表和右表能匹配上的行,任何一边对不上的行直接丢掉。用上面的数据跑:
sql复制SELECT s.学号, s.姓名, s.班级, c.科目, c.分数
FROM students s
INNER JOIN scores c ON s.学号 = c.学号;
结果:
| 学号 | 姓名 | 班级 | 科目 | 分数 |
|---|---|---|---|---|
| 1 | 小明 | 一班 | 数学 | 90 |
| 1 | 小明 | 一班 | 语文 | 85 |
| 2 | 小红 | 一班 | 数学 | 78 |
| 4 | 小丽 | 三班 | 数学 | 95 |
注意,小明出现了两行,因为他数学、语文两科都有成绩,左表里"小明"这一行被成绩表里的两行各匹配了一次,这是 JOIN 里特别常见的现象,叫行数放大。而小刚(学号3)因为没成绩,被剔除了;学号9那条成绩因为没有对应的学生,也被剔除了。
如果你脑子里对 JOIN 的印象是"取交集"——对,INNER JOIN 就是交集思维。两份名单同时对得上的人才出现在结果里。绝大多数日常查询,比如"查询下过订单的用户""查询有考试记录的学生",本质就是 INNER JOIN。这也是性能最好、最不容易出意外的 JOIN 类型,因为它天然抹掉了两边对不上的脏数据。
2.2 LEFT JOIN:左边是老板,右边是补充信息
LEFT JOIN(左外连接)是实际业务里用得最多、也最容易出 bug 的 JOIN。规则一句话:左表每一行都保留,右边能匹配上的就贴上,匹配不上就补 NULL。
sql复制SELECT s.学号, s.姓名, s.班级, c.科目, c.分数
FROM students s
LEFT JOIN scores c ON s.学号 = c.学号;
结果:
| 学号 | 姓名 | 班级 | 科目 | 分数 |
|---|---|---|---|---|
| 1 | 小明 | 一班 | 数学 | 90 |
| 1 | 小明 | 一班 | 语文 | 85 |
| 2 | 小红 | 一班 | 数学 | 78 |
| 3 | 小刚 | 二班 | NULL | NULL |
| 4 | 小丽 | 三班 | 数学 | 95 |
看到区别了没有?小刚虽然一条成绩都没有,但他还是出现在了结果里,只不过科目和分数是 NULL,意思是"这个学生存在,只是没匹配上成绩"。
怎么理解"LEFT"这个词?我一般跟新手说:
