首页/数据/SQL 速查/三表及多表连接

三表及多表连接

多个表依次连接:链式书写、逐步列出条件;每步都可能放大或缩小行数,最终结果粒度要提前想清楚。

SQL 速查数据更新于 2026-10-13

多表连接是什么

把三张以上的表依次连接取数,是报表与业务查询的常态。每一步连接都可能改变行数与粒度:一对多会放大行数,内连接会丢掉未匹配行。动手前先明确“最终一行代表什么”,再决定连接类型与条件摆放的位置。

基本信息

书写顺序按依赖链式书写:主表连接明细表,再连接各维表
结果粒度一行等于最细粒度表的一行;订单连明细后订单会重复出现
连接类型按保留侧选 INNER 或 LEFT,一段一段确认,不要整句混用
条件位置过滤主表条件放 WHERE,过滤被连接表的条件放 ON 才不改变外连接语义
核对方法分别统计各表过滤后的行数,再与最终结果行数比对
汇总口径明细放大后仍要数订单,用 COUNT(DISTINCT o.id)

三表连接示例

三表连接示例
SELECT o.id, u.name, i.product_name, i.qty
FROM orders o
JOIN users       u ON u.id = o.user_id      -- 多对一:用户键唯一则不放大行数
JOIN order_items i ON i.order_id = o.id     -- 一对多:按明细条数放大行数
WHERE o.status = 1                         -- 主表过滤条件放 WHERE
ORDER BY o.id, i.id
LIMIT 100;                                 -- 分页要保证排序键唯一,避免翻页重复

每一步的行数变化

连接步骤关系行数影响
orders 连 users多对一不放大,前提是 users 主键唯一
orders 连 order_items一对多按明细条数放大,一个订单可能多行
orders 左连 payment一对一或一对多未支付订单保留,支付列为 NULL
再连 products 维表多对一一般不放大,先确认维表键唯一
LEFT 与 INNER 混用—后面的 INNER 会把前面补出的 NULL 行过滤掉

典型使用场景

  • 订单主表串联明细与用户信息,产出明细报表
  • 补齐多张维表的描述字段:用户、商品、渠道名称
  • 日志与主体表关联做行为分析,例如订单与支付流水对照
  • 先连接明细再按主表键分组,算出每单金额与件数
  • 数据核对:把两份来源的数据连接起来,找出只在一侧存在的记录
  • 列表分页查询:主表连维表,排序键唯一才能保证分页不重不漏
链式 JOIN 是依次传递的:后面的 JOIN 作用在前面的结果集上。所以条件写在 ON 还是 WHERE、前一段用 LEFT 还是 INNER,都会影响后面每一步能看到的行。
混用外连接与内连接时,后面写的 INNER JOIN 会把前面补出的 NULL 行重新过滤掉,看起来“外连接失效”。要么统一连接类型,要么把后续条件放进 ON,并把 NULL 参与比较的情况单独处理。

易错点

  • 行数放大后直接统计:一对多明细让订单重复出现,COUNT(*) 结果偏大,应改成 COUNT(DISTINCT o.id)
  • 条件放错位置:外连接下条件写在 ON 与 WHERE 结果完全不同,先确认保留侧再摆放
  • 默认维表键唯一:实际存在重复行时连接后行数突然翻倍,连接前先验证键的唯一性
  • 连接列类型或字符集不一致:索引无法使用甚至触发隐式转换,慢查询排查先看连接列类型

数据来源与参考

  • MySQL 8.0 Reference Manual · JOIN Clause
  • PostgreSQL Documentation · Joined Tables
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌