mysql菜鸟教程

专栏导航

11.2 内连接(INNER JOIN)

在上一节我们了解了连接查询的基本概念,本节将深入探讨最常用的一种连接方式——内连接(INNER JOIN)。内连接返回两个表中满足连接条件的所有行,就像取两个集合的交集

一、什么是内连接?

内连接只返回两个表中都有匹配的记录。如果某张表的记录在另一张表中找不到对应项,则该记录不会出现在结果中。

用数学中的集合概念来理解:

  • 表A 和 表B 做内连接,结果 = A ∩ B(交集)

  • 只有匹配上的行才会被保留

二、基本语法

SELECT 列名
FROM 表1
INNER JOIN 表2 ON 表1.列 = 表2.列;

也可以省略 INNER,直接写 JOIN,默认就是内连接:

SELECT 列名
FROM 表1
JOIN 表2 ON 表1.列 = 表2.列;

如果连接条件中涉及的列名在两个表中相同,可以使用 USING 简化:

SELECT 列名
FROM 表1
JOIN 表2 USING(共同列名);

三、基础示例:学生与班级

沿用上一节的 students 和 classes 表:

students(学生表)

student_id

name

class_id


1

张三

101


2

李四

102


3

王五

101


4

赵六

NULL

-- 未分配班级

classes(班级表)

class_id

class_name

101

计算机1班

102

软件2班

内连接查询:显示有班级的学生及其班级名称

SELECT s.name, c.class_name
FROM students s
INNER JOIN classes c ON s.class_id = c.class_id;

结果

name

class_name

张三

计算机1班

李四

软件2班

王五

计算机1班

注意:学生“赵六”的 class_id 为 NULL,在班级表中没有匹配,所以没有出现在结果中。这正是内连接的特点——只保留匹配的行。

使用 USING 简化

由于连接列在两个表中都叫 class_id,可以简写:

SELECT s.name, c.class_name
FROM students s
JOIN classes c USING(class_id);

四、内连接与 WHERE 连接的对比

在老式语法中,内连接可以用 WHERE 条件实现:

SELECT s.name, c.class_name FROM students s, classes c WHERE s.class_id = c.class_id;

这种写法虽然结果一样,但有两大缺点:

  • 容易忘记 WHERE 条件,导致笛卡尔积(结果行数爆炸)

  • 连接条件和筛选条件混在一起,可读性差

因此,强烈推荐使用显式的 INNER JOIN 语法

五、多表内连接

内连接不仅限于两张表,可以连续连接多张表。例如,我们有一个包含成绩的 scores 表:

scores(成绩表)

student_id

course_name

score

1

数学

85

1

英语

90

2

数学

78

3

英语

88

现在要查询每位有成绩的学生的姓名、班级以及成绩,需要连接三张表:

SELECT s.name, c.class_name, sc.course_name, sc.score
FROM students s
JOIN classes c ON s.class_id = c.class_id
JOIN scores sc ON s.student_id = sc.student_id;

执行逻辑

  1. 先将 students 与 classes 内连接,得到有班级的学生信息。

  2. 再将结果与 scores 内连接,得到这些学生的成绩记录。

最终结果只包含既有班级又有成绩的学生(因为内连接层层筛选)。

六、ON 与 WHERE 的先后顺序

在连接查询中,ON 指定连接条件,WHERE 指定结果筛选条件。逻辑上,数据库会先执行连接(根据 ON 生成中间结果),然后再应用 WHERE 过滤。

例如,我们只想查看“计算机1班”的学生成绩:

SELECT s.name, c.class_name, sc.course_name, sc.score
FROM students s
JOIN classes c ON s.class_id = c.class_id
JOIN scores sc ON s.student_id = sc.student_id
WHERE c.class_name = '计算机1班';

这里先用 ON 连接三张表,然后 WHERE 过滤班级名称。

如果误将过滤条件写在 ON 中,会得到不同的结果:

SELECT s.name, c.class_name, sc.course_name, sc.score
FROM students s
JOIN classes c ON s.class_id = c.class_id AND c.class_name = '计算机1班'
JOIN scores sc ON s.student_id = sc.student_id;

这样会先按班级名称过滤 classes 表(只保留计算机1班),然后再与学生和成绩表连接。最终结果与之前相同,但逻辑不同。不过性能上可能差不多,但推荐将连接条件放在 ON 中,筛选条件放在 WHERE 中,以保持清晰。

七、内连接的注意事项

  1. NULL 值不参与匹配:因为 NULL 表示未知,任何值与 NULL 比较都是 UNKNOWN,所以不会匹配。上述例子中 class_id 为 NULL 的学生被排除。

  2. 连接条件必须明确:务必确保 ON 中的列在两个表中都有对应的值(或者通过外键约束保证)。

  3. 重复行问题:如果连接条件不唯一,可能导致结果行数膨胀。例如,如果一个学生有多个成绩(如数学、英语),连接后会出现多行。这是正常的,但需要确认是否符合业务预期。

  4. 性能优化

    • 为连接列(如 class_idstudent_id)建立索引。

    • 尽量先用 WHERE 过滤再连接(优化器通常会自行优化,但明确过滤有助于提升效率)。

    • 避免不必要的连接。

八、综合练习

假设我们有如下三张表:

  • users(用户ID、用户名)

  • orders(订单ID、用户ID、订单日期)

  • order_items(订单ID、商品名称、数量、单价)

请用内连接查询出所有有订单的用户及其订单详情。

参考答案

SELECT u.username, o.order_id, o.order_date, oi.product_name, oi.quantity, oi.unit_price
FROM users u
JOIN orders o ON u.user_id = o.user_id
JOIN order_items oi ON o.order_id = oi.order_id
ORDER BY u.username, o.order_date;

九、小结

特性

说明

作用

返回两个表中满足连接条件的行的交集

语法

表1 INNER JOIN 表2 ON 条件

 或简写 

JOIN

结果特点

只保留匹配的行,不匹配的行被丢弃

多表连接

可以连续使用 JOIN 连接多张表

与WHERE区别

显式 JOIN 更清晰、更安全

常见场景

根据外键关系关联查询主从表信息

内连接是日常开发中使用频率最高的连接类型,它帮助我们高效地从多个相关表中提取整合后的数据。


所有评论

关于我 备案号:蜀ICP备2023042032号-1