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查询结果为空,尽量避免。
相关推荐
g10565591392 小时前
LAMP博客平台Wordpress实战
android·mysql·nginx·php
我不是疯子是傻子2 小时前
Qt CAN通信周期发送抖动?实测定时器精度校准与时间戳补偿方案
开发语言·数据库·qt
这个DBA有点耶2 小时前
数据库迁移怎么做到“零翻车“:金仓 KDMS/KDTS/KFS 工具链实测
数据库·架构·dba
名字还没想好☜3 小时前
Next.js 用 Server Components 直连数据库:去掉 API 层的边界,和三条别踩的安全红线
前端·javascript·数据库·安全·react·next.js
迷迭香yy4 小时前
行业板块轮动因子实战从板块资金到因子建模的本地化Python全流程
数据库·人工智能·python
SelectDB4 小时前
抖音集团 实时数据仓库:Apache Doris / SelectDB 的技术能力与实践
数据库
SelectDB5 小时前
网易 日志与时序数据分析:Apache Doris / SelectDB 的技术能力与实践
数据库
weixin_539446785 小时前
Navicat Premium 17报缺少ODBC驱动
数据库
这个DBA有点耶5 小时前
迁移中的数据一致性挑战:如何确保百万行数据“搬得对”
mysql·架构·dba