在 SQL 里做连接查询,最常用的是三种写法思路:用 JOIN 关键字显式连表、用 FROM 多表加 WHERE 条件隐式连表、以及用子查询或 UNION 衔接。三者里 JOIN 最清晰、最推荐,隐式写法如果漏掉连接条件,很容易炸出笛卡尔积。很多初学者把多张表往 FROM 后一塞就开始查,结果返回了几万行自己都懵了。本文用最小示例讲清三种写法的写法、效率和边界,并给出一张选型表,看完你就能按场景选对连接方式,不再被莫名暴涨的行数坑到。

先看结论
先给你一张选型表,省得在三种写法之间纠结:
| 你想做的事 | 推荐写法 | 原因 |
|---|---|---|
| 明确连两张表、可读性优先 | JOIN 显式连接 |
连接条件写在 ON 上,最清晰、最不易漏 |
| 快速临时查询、表很少 | FROM 多表 + WHERE |
写法短,但容易漏条件 |
| 先算子集再关联主表 | 子查询 / UNION |
逻辑分步,适合复杂条件 |
一句话记住:正式写法和代码评审,优先用 JOIN;临时排查可以用 FROM 多表,但务必带上连接条件;需要分步聚合就用子查询。
一、JOIN 显式连接(推荐)
JOIN 是最标准、最不容易出错的写法,连接条件明确写在 ON 后面,谁和谁连、用什么字段连一目了然。
SELECT u.name, o.amount
FROM users u
INNER JOIN orders o ON u.id = o.user_id;
上面这段把 users 和 orders 两张表用 user_id 关联起来,只保留两表都能匹配上的记录。预期结果(未在本机执行):返回每一对能匹配上的用户与订单组合行,例如 张三 | 200。如果你还不熟悉 SQL 的查询基础,可以先过一遍 SQL 基础教程 里 SELECT 与多表查询的章节再回来读。实际动手时,建议先在测试库里运行这条查询,检查返回行数是否符合预期;如果行数远多于两张表的匹配对数,基本就是漏写了连接条件。验证连接是否真的生效,最快的方式是把 ON 里的字段临时改成不可能相等的值,看结果是否瞬间清空。关于连接语法的参数细节,可以查 MySQL 速查手册 里对 JOIN 的速查条目。
从版本边界上说,INNER JOIN、LEFT JOIN 这类显式连接在所有主流数据库(MySQL、PostgreSQL、SQL Server)都一致支持,不用愁兼容性。性能上,数据库优化器对显式 JOIN 的连接顺序和索引利用最有效,是线上查询的默认选择。
二、FROM 多表 + WHERE 隐式连接
这是更早期的写法,把多张表都列在 FROM 后面,连接条件塞进 WHERE。写法短,但所有“过滤”和“连接”混在一起,稍不注意就会漏掉连接条件。
SELECT u.name, o.amount
FROM users u, orders o
WHERE u.id = o.user_id;
这段和第一节的 JOIN 返回同样的结果,只是把连接条件放到了 WHERE 里。预期结果(未在本机执行):同样返回用户与订单的匹配组合行。需要安装并启动好 MySQL 后,在客户端里执行这条查询即可运行验证。前提是两张表都已经建好并插了数据,否则会直接报“表不存在”的错误。
三、子查询与 UNION 衔接
当连接逻辑需要先算出一部分子集、再和主表关联时,子查询更直观;当要把结构相同的多段结果拼起来,则用 UNION。
SELECT name FROM users
WHERE id IN (SELECT user_id FROM orders WHERE amount > 100);
这段先查出“消费超过 100 的订单对应的 user_id”,再回主表取这些用户的名字。预期结果(未在本机执行):返回所有下过百元以上订单的用户姓名。边界要注意:子查询返回的结果集过大时,IN 的性能会下降,这时更适合改写成 JOIN;UNION 则要求各段列数一致,并且默认去重,需要保留重复时要用 UNION ALL。更系统的 MySQL 语法可以看 MySQL 入门教程 的子查询章节。
四、横向对比与踩坑清单
把三种写法摆在一起,差异就很清楚:
| 维度 | JOIN 显式 | FROM 多表 | 子查询 |
|---|---|---|---|
| 连接条件位置 | ON 明确写出 | 混在 WHERE | 单独一段 |
| 漏条件风险 | 低 | 高(易笛卡尔积) | 中 |
| 可读性 | 高 | 低 | 中 |
选型建议很明确:代码评审和线上查询,默认用 JOIN;临时排查可以用 FROM 多表,但必须带上 ON 等价的条件;需要分步聚合或拼结果集时用子查询或 UNION。
下面这几条是实际写查询时最常卡住的点,每条都给了现象、原因和修复办法。
- 现象:FROM 后面塞了两张表,运行后返回行数暴涨到几万行。
原因:漏写了连接条件,两张表做了笛卡尔积。
修复:在 WHERE 里补上u.id = o.user_id这样的连接条件,或改写成显式 JOIN。
- 现象:用 LEFT JOIN 却拿不到右表的空匹配行。
原因:把右表的过滤写进了 WHERE,等于把外连接又变回内连接。
修复:右表的过滤条件要写在 ON 上,而不是 WHERE 上。
- 现象:IN 子查询很慢。
原因:子查询返回大量 id,IN 列表膨胀导致性能下降。
修复:改写成 JOIN,让优化器用索引做连接,速度通常明显提升。
- 现象:UNION 之后发现重复行被吞了。
原因:UNION 默认去重,会把“恰好相同”的行合并。
修复:确认需要保留重复时用 UNION ALL,避免误删数据。


总结
SQL 连接查询就三件事:正式写法用 JOIN 最清晰,临时排查可用 FROM 多表但务必带连接条件,需要分步聚合用子查询或 UNION。选错写法,最常见的后果就是漏条件炸出笛卡尔积。
要点带走:
- JOIN 把连接条件写在 ON 上,可读性最高、漏条件风险最低;
- FROM 多表写法短,但连接条件和过滤混在一起,极易漏写;
- 子查询适合先算子集再关联,结果集过大时改 JOIN 更稳;
- UNION 默认去重,要保留重复就改用 UNION ALL。
下一步如果你要优化慢查询,建议先从把隐式连接改造成显式 JOIN 开始,再去看执行计划里的连接顺序。
延伸学习
想把 SQL 与数据库这块系统补齐,可以按这个顺序来:
- 先过一遍 SQL 入门课程,把多表查询和索引的基础铺平;
- 那篇 SQL 连接查询写法详解 从内连到外连把三种写法又讲了一遍,和本文互为补充;
- MySQL 多表与 JOIN 指南 从效率角度讲了 FROM 多表与 JOIN 的差别,调优时很有参考价值。
常见问题
Q:JOIN 和 FROM 多表加 WHERE 结果一样吗?
A:在连接条件都写全的前提下,结果一样。区别在于可读性:JOIN 把连接条件放在 ON 上,FROM 多表把所有条件混在 WHERE 里,后者更容易漏写连接条件、炸出笛卡尔积,所以正式写法优先用 JOIN。
Q:LEFT JOIN 为什么拿不到右表的空行?
A:多半是把右表的过滤写进了 WHERE。WHERE 会在连接之后再次过滤,把右表为空的行又筛掉了,相当于变回内连接。正确做法是将右表相关的过滤写在 ON 子句里。
Q:子查询和 JOIN 该选哪个?
A:结构简单、子查询返回集不大时,两者都行,JOIN 通常更易被优化器用好索引。当子查询结果集很大、IN 列表膨胀导致变慢时,改写成 JOIN 往往能明显提速,是调优的常见第一步。

TRAE-AI编程



