MySQL 联合查询全解析:从基础到实战

在数据库开发中,我们经常需要从多个表中获取数据来组成完整的信息。比如想知道某个学生的姓名、班级名称、各科成绩,这些数据可能分散在学生表、班级表和成绩表中。这时候,联合查询就成了必备技能。本文将从底层原理到实战案例,全面讲解 MySQL 联合查询的核心知识。

一、为什么需要联合查询?

数据库设计遵循范式原则,目的是减少数据冗余。这意味着一个完整的业务信息会被拆分到多个表中:

  • 学生的基本信息存在student表(姓名、学号、班级编号等)
  • 班级信息存在class表(班级编号、班级名称等)
  • 成绩信息存在score表(学生 ID、课程 ID、分数等)

要获取 "学生姓名 + 班级名称 + 成绩" 这样的完整信息,就必须将多个表 "联合" 起来查询 —— 这就是联合查询的核心价值。

二、MySQL 联合查询的底层逻辑

你知道 MySQL 是如何处理多表查询的吗?核心步骤只有两步:

  1. 计算笛卡尔积:将参与查询的所有表进行组合,生成一张临时表。例如学生表(3 条数据)和班级表(3 条数据)的笛卡尔积会产生 3×3=9 条数据(见下表)。

    学生表。编号姓名班级编号班级表。编号班级名称
    1张三11java113
    1张三12java78
    1张三13C++110
    ...............
  2. 过滤无效数据:通过表之间的关联关系(如student.班级编号 = class.编号),从笛卡尔积中筛选出有效数据。

三、核心连接方式:内连接、外连接、自连接

3.1 内连接(INNER JOIN):只取匹配的数据

内连接是最常用的连接方式,只返回两个表中满足连接条件的记录

语法(两种方式):
-- 方式1:逗号分隔表,where指定连接条件
select 字段 from 表1, 表2 where 表1.关联字段 = 表2.关联字段;

-- 方式2:JOIN关键字,on指定连接条件(推荐,更清晰)
select 字段 from 表1 [inner] join 表2 on 表1.关联字段 = 表2.关联字段;
示例:查询 "唐三藏" 的成绩
-- 关联学生表(student)和成绩表(score)
select s.name, sc.score 
from student s 
join score sc on sc.student_id = s.id 
where s.name = '唐三藏';

结果会返回唐三藏的所有成绩记录:

namescore
唐三藏70.5
唐三藏98.5
唐三藏33
唐三藏98

3.2 外连接:保留不匹配的数据

内连接只返回匹配的记录,但有时我们需要保留某张表的所有记录(即使没有匹配)。外连接分为两种:

  • 左外连接(LEFT JOIN):保留左表所有记录,右表无匹配则显示 NULL。
  • 右外连接(RIGHT JOIN):保留右表所有记录,左表无匹配则显示 NULL。

注意:MySQL 不支持全外连接(FULL JOIN),但可通过LEFT JOIN + UNION + RIGHT JOIN模拟。

示例 1:查询所有学生的考试记录(包括没参加考试的)
-- 左表为student,右表为score,保留所有学生
select s.name, sc.score 
from student s 
left join score sc on s.id = sc.student_id;

结果中,"不想毕业" 同学因未参加考试,score 字段为 NULL:

namescore
唐三藏70.5
......
不想毕业NULL
示例 2:查询所有班级(包括没有学生的)
-- 右表为class,保留所有班级
select c.name, s.name 
from student s 
right join class c on s.class_id = c.id;

结果中,"前端 001 班" 因没有学生,student.name 为 NULL:

班级名称name
Java001 班唐三藏
C++001 班宋江
前端 001 班NULL

3.3 自连接:表与自身的连接

自连接是一种特殊的连接方式 ——表自己和自己连接,常用于 "行与行之间的比较"。使用时必须给表起不同的别名。

示例:查询 MySQL 成绩比 Java 高的学生
-- 成绩表score分别用s1(MySQL)和s2(Java)作为别名
select s1.student_id, s1.score as mysql_score, s2.score as java_score
from score s1, score s2
where s1.student_id = s2.student_id  -- 同一学生
  and s1.course_id = 3  -- MySQL的课程ID
  and s2.course_id = 1  -- Java的课程ID
  and s1.score > s2.score;

结果:

student_idmysql_scorejava_score
198.570.5
36833

四、子查询:嵌套在查询中的查询

子查询(嵌套查询)是将一个查询的结果作为另一个查询的条件或数据源。根据返回结果的行数 / 列数,可分为:

  • 单行子查询:返回 1 行 1 列,用=>等比较符。
  • 多行子查询:返回多行 1 列,用INNOT IN等。
  • 多列子查询:返回多行多列,用(col1, col2) IN (...)
示例 1:查询 "不想毕业" 的同班同学(单行子查询)
-- 内层查询获取班级ID,外层查询用=匹配
select name 
from student 
where class_id = (select class_id from student where name = '不想毕业');
示例 2:查询 Java 或 MySQL 课程的成绩(多行子查询)
-- 内层查询返回多个课程ID,外层用IN匹配
select * from score 
where course_id in (select id from course where name in ('Java', 'MySQL'));

五、合并查询:UNION 与 UNION ALL

当需要合并两个查询的结果时,可使用UNIONUNION ALL

  • UNION:合并结果并自动去重。
  • UNION ALL:合并结果但保留重复行(效率更高)。
示例:合并两个学生表的数据
-- 合并student表(id<3)和student1表,自动去重
select * from student where id < 3
union
select * from student1;

六、实用技巧:插入查询结果与创建表

联合查询的结果不仅可以直接查看,还能用于插入数据或创建新表:

插入查询结果

-- 将C++001班的学生复制到student1表
insert into student1 (name, sno, class_id)
select s.name, s.sno, s.class_id
from student s, class c
where s.class_id = c.id and c.name = 'C++001班';

根据查询结果创建表

-- 将查询结果保存为新表
create table java_students as
select s.name, c.name as class_name
from student s, class c
where s.class_id = c.id and c.name = 'Java001班';

总结

联合查询是 MySQL 中处理多表数据的核心技术,掌握以下要点将大幅提升你的数据处理能力:

  • 内连接用于获取两表匹配的数据;
  • 外连接用于保留某一表的所有记录;
  • 自连接用于行与行的比较;
  • 子查询让复杂逻辑分步实现;
  • UNION 用于合并多个查询结果。

实际开发中,需根据业务场景选择合适的查询方式,并注意通过索引优化连接效率(尤其是多表连接时)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值