MySQL联合查询(多表查询)

MySQL联合查询(多表查询)知识点总结

范式设计后数据拆分到多张表,想要拿到完整业务数据就需要联合查询,包含:内连接、外连接、自连接、子查询、合并查询、插入查询结果。

一、联合查询底层原理:笛卡尔积

  1. 多表查询会先做笛卡尔积,把A表每一行和B表每一行全部组合,生成巨大临时结果集。
  2. 再通过连接条件过滤无效组合,留下符合关联关系的数据。
  3. ⚠️注意:参与表越多、数据量越大,笛卡尔积结果集会爆炸,性能变差,尽量少关联过多表。

实操技巧:给表起别名简化书写;多表存在同名字段,必须使用表名.列名消除歧义。

测试用表说明

用到四张表:

  • student学生表、class班级表、course课程表、score成绩表。

二、表连接分类

1. 内连接 INNER JOIN

只返回两张表满足连接条件的记录 ,两边匹配不到的数据不会出现在结果。

两种等价写法:

sql 复制代码
-- 写法1:逗号 + where
select 字段 from 表1,表2 where 连接条件 and 其他条件;

-- 写法2:JOIN ... ON(推荐,连接条件和普通过滤条件分离)
select 字段 from 表1 inner join 表2 on 连接条件 where 其他条件;

示例:查询唐三藏所有考试成绩;多表联查学生+班级+课程+成绩;内连接不会出现没有成绩的学生。

2. 外连接

MySQL支持左外连接、右外连接,不支持全外连接

类型 说明 语法
左外连接 LEFT JOIN 保留左表全部行 ,右表匹配不到填充NULL select * from A left join B on 连接条件;
右外连接 RIGHT JOIN 保留右表全部行 ,左表匹配不到填充NULL select * from A right join B on 连接条件;

典型案例:

  1. 左连接:查询没有参加考试的学生 ,学生左表,成绩右表;判断成绩字段IS NULL筛选无成绩学生。
  2. 右连接:查询没有学生的班级,班级放join右侧,学生放左侧,学生字段为NULL即为空班级。

小技巧:左连接可以改写为右连接,开发优先习惯用左连接。

⚠️外连接关联条件写在ON后,不要写在WHERE,写where会退化成内连接。

3. 自连接

一张表自己和自己做连接 ,必须给同一张表起两个不同别名 ,否则报错。

用途:实现行与行之间对比 。

示例:同一个学生,比较MySQL课程成绩和Java课程成绩,把score表起两个别名s1、s2做关联。

三、子查询(嵌套查询)

子查询:将一条select的查询结果,当做另一条SQL的条件/临时表。分为四类:

  1. 单行子查询 :子查询返回1行结果,使用=判断。

    sql 复制代码
    select * from student where class_id = (select class_id from student where name='不想毕业');
  2. 多行子查询 :子查询返回多条,使用IN / NOT IN

    sql 复制代码
    select * from score where course_id in (select id from course where name='Java' or name='MySQL');
  3. 多列子查询 :子查询返回多列,外层where括号内写多列匹配 (col1,col2) IN (...),适合查找重复记录。

  4. FROM后的子查询(派生表/临时表) :把子查询结果当成一张临时表,必须给临时表起别名。

sql 复制代码
select * from score s, (子查询SQL) tmp where s.score > tmp.score;

注意:子查询可以多层嵌套,复杂SQL可读性变差,复杂场景优先改用表连接。

四、合并查询 UNION / UNION ALL

把多条SELECT结果集上下拼接 ,要求前后select返回列数量、类型一致,列名以第一条select为准。

  1. UNION:合并并且自动去重,消耗性能;
  2. UNION ALL:直接拼接,不去重,保留全部数据,性能更高;

业务如果不需要去重优先用UNION ALL。

示例:学生表id<3的数据 union 另一张student1全部数据。

五、插入查询结果

语法:INSERT INTO 目标表(列...) SELECT ...

把select查询出来的结果,直接插入目标表,常用于数据复制、迁移。

sql 复制代码
insert into student1(name,sno,age,gender,enroll_date,class_id) 
select s.name, s.sno, s.age, s.gender, s.enroll_date, s.class_id
from student s join class c on s.class_id=c.id where c.name='C++001班';

六、核心易错点整理

  1. 笛卡尔积风险:多表必须写连接条件,忘记条件会产生海量无效数据;
  2. 字段重名:多表同名字段必须加表别名限定,否则报Column ... is ambiguous;
  3. 外连接:匹配条件写ON,业务过滤写WHERE,不要把外连接匹配条件挪到where;
  4. from后面的子查询,临时表必须写别名,语法强制;
  5. UNION和UNION ALL区别:UNION自动去重,性能差;UNION ALL直接拼接;
  6. 自连接:同一张表做连接,必须设置两个不同别名;
  7. IN子查询注意NULL:子查询结果存在NULL时,NOT IN查询结果为空,尽量避免。
相关推荐
codigger1 小时前
线上数据库连接池打满:从应急止损到架构根治的完整方案
数据库·sql·程序员
倔强的石头_1 小时前
集中式与分布式怎么选?我把手头11套系统重新过了一遍秤
数据库
挖掘狂人1 小时前
线上数据库连接池打满:从应急止损到架构根治的完整方案
数据库·sql·程序员
Rainmicro2 小时前
【无标题】
java·数据库·算法
Thanks_ks2 小时前
MySQL 的索引是什么?用图书馆的目录讲明白
数据库·sql·mysql·索引·联合索引·explain·慢查询优化
CoderYanger8 小时前
Java EE 进阶:8.MyBatis 操作数据库(入门)(第二弹)
java·数据库·spring boot·spring·面试·java-ee·mybatis
wafrdggh11 小时前
2026电商快递批量查询怎么用?固乔助手模板设置评测
大数据·数据库·小程序
一个天蝎座 白勺 程序猿11 小时前
KingbaseES数据库归档重做日志文件管理:从配置到运维的实战指南
运维·数据库·oracle·kingbasees·金仓数据库
龙腾AI白云14 小时前
仿真到现实(Sim-to-Real)迁移:跨越仿真与现实鸿沟
数据库·机器学习·plotly·知识图谱·tornado
freejackman17 小时前
【实战二】字段级血缘追踪:拆解 AST 迷局,精准穿透函数链与子查询
大数据·数据库·sql