讲解

关系型数据库把数据拆在多张表里:订单表只存 student_id 和 course_id,想知道「谁买了什么课」就要把表连起来。INNER JOIN(内连接)按条件把两张表的行配对:FROM orders JOIN students ON orders.student_id = students.id,ON 后面是配对条件。只有两边都能配上对的行才出现在结果里——配不上的一侧直接消失。

结果集可以这样理解:左表每一行去右表找满足 ON 条件的行,找到几个就配对几次,一个都找不到就不出现。所以连接后的行数可能多于或少于任一原表。本教程的 orders 表里第 12 号订单的 student_id 是 9,而学生表里没有 9 号学生,内连接时这条订单就不会出现——这是理解内连接「只保留匹配行」的最好例子。

连接可以串起来:三表连接 orders JOIN students JOIN courses 一次拿到学生姓名、课程标题和订单金额。多表同名列要用「表名.列名」或表别名限定,比如 orders.id 和 students.id,否则报「ambiguous column name」。INNER 关键字可以省略,写 JOIN 默认就是内连接。

示例

订单连上学生,看看每笔订单是谁下的(注意:12 号订单的学生不存在,不会出现在结果里):

SELECT orders.id, students.name, orders.amount, orders.status FROM orders JOIN students ON orders.student_id = students.id ORDER BY orders.id;

三表连接,一次看到「谁、买了什么课、花了多少钱」:

SELECT s.name AS student, c.title AS course, o.amount FROM orders AS o JOIN students AS s ON o.student_id = s.id JOIN courses AS c ON o.course_id = c.id ORDER BY o.id;

连接后再聚合:每个学生(有订单的)的总消费:

SELECT s.name, SUM(o.amount) AS total_spent FROM orders AS o JOIN students AS s ON o.student_id = s.id GROUP BY s.name ORDER BY total_spent DESC;

常见坑

  • 忘记或写错 ON 条件:不写 ON 的逗号式连接会产生笛卡尔积——8 个学生 × 12 条订单 = 96 行毫无意义的组合。行数突然爆炸时第一反应就是检查连接条件。
  • ON 条件写成等值以外的关系:99% 的连接是外键等于主键,把 ON 写成 > 或 != 几乎都是笔误,结果行数会莫名其妙地膨胀。
  • 同名列不加限定:两张表都有 id,SELECT id 会报歧义错误。养成「连接查询里所有列都带表名前缀」的习惯,可读性也更好。
  • 以为内连接保留所有行:任一侧匹配不上,那行就没了。想保留全部学生(包括没下过单的)要用下一章的 LEFT JOIN。

小结

INNER JOIN 按 ON 条件配对两表的行,只保留双方都匹配的组合;多表可连续连接,同名列要限定。下一节学习保留单侧全部行的外连接。