数据库---Day8 多表联合查询

本系列可作为数据库学习系列的笔记,文中提到的一些练习的代码,小编会将代码复制下来,大家复制下来就可以练习了,方便大家学习。

点赞关注不迷路!您的点赞、关注和收藏是对小编最大的支持和鼓励!

系列文章目录

JAVA初阶---------已更完

JAVA数据结构---------已更完

数据库---Day 1 数据库基础

数据库---Day2 数据库操作

数据库---Day3 数据类型

数据库---Day4 数据表的操作

数据库---Day5 数据表的增删改查

数据库---Day6 数据库约束

数据库---Day7 数据表设计

数据库---Day8 多表联合查询


目录

目录

系列文章目录

目录

前言

一、本节学习目标

二、联合查询简介(为什么必须学)

[2.1 为什么要使用联合查询](#2.1 为什么要使用联合查询)

[2.2 多表联合查询时 MySQL 内部是如何计算的](#2.2 多表联合查询时 MySQL 内部是如何计算的)

[步骤 1:先做笛卡尔积(全排列)](#步骤 1:先做笛卡尔积(全排列))

[步骤 2:生成巨大临时表](#步骤 2:生成巨大临时表)

[步骤 3:根据连接条件过滤](#步骤 3:根据连接条件过滤)

[步骤 4:返回最终结果](#步骤 4:返回最终结果)

[2.3 构造练习案例数据(全文统一使用)](#2.3 构造练习案例数据(全文统一使用))

三、一个完整的联合查询全过程(最标准步骤)

[步骤 1:确定参与查询的表](#步骤 1:确定参与查询的表)

[步骤 2:添加连接条件](#步骤 2:添加连接条件)

[步骤 3:添加业务查询条件](#步骤 3:添加业务查询条件)

[步骤 4:精简查询字段(不要 SELECT *)](#步骤 4:精简查询字段(不要 SELECT *))

[步骤 5:使用表别名(简化代码,开发标准写法)](#步骤 5:使用表别名(简化代码,开发标准写法))

[四、内连接(INNER JOIN)](#四、内连接(INNER JOIN))

[4.1 内连接定义](#4.1 内连接定义)

[4.2 内连接两种语法](#4.2 内连接两种语法)

[写法 1:逗号分隔(隐式内连接)](#写法 1:逗号分隔(隐式内连接))

[写法 2:JOIN ON(显式内连接,推荐)](#写法 2:JOIN ON(显式内连接,推荐))

[4.3 内连接经典案例(全部来自 PDF)](#4.3 内连接经典案例(全部来自 PDF))

[案例 1:查询 "唐三藏" 的所有成绩](#案例 1:查询 “唐三藏” 的所有成绩)

[案例 2:查询所有同学的总成绩](#案例 2:查询所有同学的总成绩)

[案例 3:三表联查(学生 + 课程 + 成绩)](#案例 3:三表联查(学生 + 课程 + 成绩))

[五、外连接(LEFT / RIGHT JOIN)](#五、外连接(LEFT / RIGHT JOIN))

[5.1 左外连接(LEFT JOIN)](#5.1 左外连接(LEFT JOIN))

定义

语法

经典案例:查询没有参加考试的学生

[5.2 右外连接(RIGHT JOIN)](#5.2 右外连接(RIGHT JOIN))

定义

语法

经典案例:查询没有学生的班级

六、自连接(自己连接自己)

[6.1 什么是自连接](#6.1 什么是自连接)

[6.2 自连接使用场景](#6.2 自连接使用场景)

[6.3 经典案例(PDF 原题)](#6.3 经典案例(PDF 原题))

需求:

七、子查询(嵌套查询)

[7.1 子查询定义](#7.1 子查询定义)

[7.2 子查询分类](#7.2 子查询分类)

[7.3 单行子查询](#7.3 单行子查询)

[案例:查询和 "不想毕业" 同班的同学](#案例:查询和 “不想毕业” 同班的同学)

[7.4 多行子查询](#7.4 多行子查询)

[案例:查询 Java 或 MySQL 课程的成绩](#案例:查询 Java 或 MySQL 课程的成绩)

[7.5 多列子查询](#7.5 多列子查询)

案例:查询重复录入的成绩

[7.6 FROM 子句中的子查询(临时表)](#7.6 FROM 子句中的子查询(临时表))

[案例:查询比 Java001 班平均分高的成绩](#案例:查询比 Java001 班平均分高的成绩)

[八、合并查询(UNION / UNION ALL)](#八、合并查询(UNION / UNION ALL))

[8.1 作用](#8.1 作用)

[8.2 UNION](#8.2 UNION)

[8.3 UNION ALL](#8.3 UNION ALL)

[九、插入查询结果(INSERT INTO ... SELECT)](#九、插入查询结果(INSERT INTO … SELECT))

[9.1 作用](#9.1 作用)

[9.2 语法](#9.2 语法)

[9.3 案例(PDF 原题)](#9.3 案例(PDF 原题))

[十、全文超详细总结(面试 / 考试必背)](#十、全文超详细总结(面试 / 考试必背))

[10.1 联合查询核心](#10.1 联合查询核心)

[10.2 内连接](#10.2 内连接)

[10.3 外连接](#10.3 外连接)

[10.4 自连接](#10.4 自连接)

[10.5 子查询](#10.5 子查询)

[10.6 合并查询](#10.6 合并查询)

[10.7 插入查询](#10.7 插入查询)

总结


前言

小编作为新晋码农一枚,会定期整理一些写的比较好的代码,作为自己的学习笔记,会试着做一下批注和补充,如转载或者参考他人文献会标明出处,非商用,如有侵权会删改!欢迎大家斧正和讨论!

在关系型数据库中,数据永远不会全部存在一张表里。因为我们要遵循数据库范式,要减少冗余、避免异常、保证结构清晰,所以数据一定会被拆分到多张表中。

当你需要查询一条完整业务信息 时 ------ 比如 "学生姓名 + 班级名称 + 课程名称 + 考试分数"------ 就必须使用多表联合查询

联合查询是 MySQL 最核心、最常用、面试最高频的知识点之一。

一、本节学习目标

  1. 了解联合查询的计算过程
  2. 掌握内连接、左外连接、右外连接、自连接查询
  3. 掌握子查询合并查询
  4. 掌握插入查询结果根据查询结果创建表

二、联合查询简介(为什么必须学)

2.1 为什么要使用联合查询

数据库设计遵循三大范式,数据会被拆分成多张表。

例如:

  • 学生信息 → student 表
  • 班级信息 → class 表
  • 课程信息 → course 表
  • 成绩信息 → score 表

当你需要查询:"学生姓名、班级名称、课程名称、考试分数" 这些信息分别存在四张表里

你必须把多张表按关联条件组合起来查询 ,这就是联合查询

一句话:联合查询 = 把多张表按关系拼在一起,查出完整信息。

2.2 多表联合查询时 MySQL 内部是如何计算的

这是面试高频题,也是理解联合查询的核心钥匙

MySQL 做多表查询时,内部执行步骤如下:

步骤 1:先做笛卡尔积(全排列)

把所有参与查询的表,进行全量组合 。例如:学生表 8 条数据 × 班级表 3 条数据 = 24 条临时数据

步骤 2:生成巨大临时表

所有字段拼在一起,形成一张超大临时表。里面99% 都是无效数据

步骤 3:根据连接条件过滤

使用 whereon 条件过滤无效数据。只保留匹配正确的记录。

步骤 4:返回最终结果

⚠️ 重要结论:**表越多、数据越大,笛卡尔积越大,性能越低。**实际开发中,尽量控制联合表的数量。

2.3 构造练习案例数据(全文统一使用)

下面是全文所有案例使用的初始化 SQL,你必须先执行一遍。

sql 复制代码
-- 课程表
INSERT INTO course (name) VALUES 
('Java'), ('C++'), ('MySQL'), ('操作系统'), ('计算机网络'), ('数据结构');

-- 班级表
INSERT INTO class(name) VALUES 
('Java001班'), ('C++001班'), ('前端001班');

-- 学生表
INSERT INTO student (name, sno, age, gender, enroll_date, class_id) VALUES
('唐三藏', '100001', 18, 1, '1986-09-01', 1),
('孙悟空', '100002', 18, 1, '1986-09-01', 1),
('猪悟能', '100003', 18, 1, '1986-09-01', 1),
('沙悟净', '100004', 18, 1, '1986-09-01', 1),
('宋江',    '200001', 18, 1, '2000-09-01', 2),
('武松',    '200002', 18, 1, '2000-09-01', 2),
('李逹',    '200003', 18, 1, '2000-09-01', 2),
('不想毕业','200004', 18, 1, '2000-09-01', 2);

-- 成绩表
INSERT INTO score (score, student_id, course_id) VALUES
(70.5, 1, 1),(98.5, 1, 3),(33, 1, 5),(98, 1, 6),
(60, 2, 1),(59.5, 2, 5),
(33, 3, 1),(68, 3, 3),(99, 3, 5),
(67, 4, 1),(23, 4, 3),(56, 4, 5),(72, 4, 6),
(81, 5, 1),(37, 5, 5),
(56, 6, 2),(43, 6, 4),(79, 6, 6),
(80, 7, 2),(92, 7, 6);

三、一个完整的联合查询全过程(最标准步骤)

需求:查询学生姓名为 "宋江" 的详细信息,包括学生信息 + 班级名称。

下面是最标准、最规范、最容易理解的 5 步写法。

步骤 1:确定参与查询的表

我们需要:

  • 学生表:student
  • 班级表:class
sql 复制代码
SELECT * FROM student, class;

执行后你会发现:**出现了 24 条记录(8×3)**这就是笛卡尔积,大量无效数据。

步骤 2:添加连接条件

学生表的 class_id = 班级表的 id

sql 复制代码
SELECT * FROM student, class 
WHERE student.class_id = class.id;

现在只剩下有效匹配数据

步骤 3:添加业务查询条件

我们要查 "宋江"。

注意:两个表都有 name 字段,必须用 表名。列名 指定,否则报错:

sql 复制代码
Column 'name' in where clause is ambiguous

正确写法:

sql 复制代码
SELECT * FROM student, class 
WHERE student.class_id = class.id 
AND student.name = '宋江';

步骤 4:精简查询字段(不要 SELECT *)

sql 复制代码
SELECT 
  student.id,
  student.name,
  student.sno,
  student.age,
  class.name 
FROM student, class 
WHERE student.class_id = class.id 
AND student.name = '宋江';

步骤 5:使用表别名(简化代码,开发标准写法)

sql 复制代码
SELECT 
  s.id,
  s.name,
  s.sno,
  c.name AS class_name
FROM student s, class c 
WHERE s.class_id = c.id 
AND s.name = '宋江';

执行结果:

sql 复制代码
5 | 宋江 | 200001 | C++001班

四、内连接(INNER JOIN)

内连接是最常用、最基础的表连接方式。

4.1 内连接定义

只返回两张表能够完全匹配 的数据。任何一张表中没有匹配的数据,不会出现在结果里

4.2 内连接两种语法

写法 1:逗号分隔(隐式内连接)

sql 复制代码
SELECT 字段 
FROM 表1 别名1, 表2 别名2 
WHERE 连接条件 AND 其他条件;

写法 2:JOIN ON(显式内连接,推荐)

sql 复制代码
SELECT 字段 
FROM 表1 别名1 
INNER JOIN 表2 别名2 
ON 连接条件 
WHERE 其他条件;

4.3 内连接经典案例(全部来自 PDF)

案例 1:查询 "唐三藏" 的所有成绩

sql 复制代码
SELECT s.name, sc.score 
FROM student s 
JOIN score sc ON sc.student_id = s.id 
WHERE s.name = '唐三藏';

结果:

sql 复制代码
唐三藏 | 70.5
唐三藏 | 98.5
唐三藏 | 33
唐三藏 | 98

案例 2:查询所有同学的总成绩

sql 复制代码
SELECT s.name, SUM(sc.score) 
FROM student s, score sc 
WHERE sc.student_id = s.id 
GROUP BY s.id;

案例 3:三表联查(学生 + 课程 + 成绩)

sql 复制代码
SELECT 
  s.id,
  s.name,
  c.name AS course_name,
  sc.score
FROM student s, course c, score sc 
WHERE 
  s.id = sc.student_id 
  AND c.id = sc.course_id
ORDER BY s.id;

注意:结果中没有 "不想毕业",因为他没有成绩,内连接不显示。

五、外连接(LEFT / RIGHT JOIN)

内连接只显示匹配成功 的数据。但现实需求中,我们经常需要:显示某张表的全部数据,不管另一张表有没有匹配。

这时就需要外连接

外连接分三种:

  1. 左外连接(LEFT JOIN)
  2. 右外连接(RIGHT JOIN)
  3. 全外连接(FULL JOIN)

⚠️ MySQL 不支持 FULL JOIN

5.1 左外连接(LEFT JOIN)

定义

  • LEFT JOIN 左边的表 为基准
  • 左表所有记录全部显示
  • 右表没有匹配 → 显示 NULL

语法

sql 复制代码
SELECT 字段 
FROM 表1 
LEFT JOIN 表2 
ON 连接条件;

经典案例:查询没有参加考试的学生

sql 复制代码
SELECT s.* 
FROM student s 
LEFT JOIN score sc ON sc.student_id = s.id 
WHERE sc.score IS NULL;

结果:

sql 复制代码
8 | 不想毕业 | 200004 | 18 | 1 | 2000-09-01 | 2

5.2 右外连接(RIGHT JOIN)

定义

  • RIGHT JOIN 右边的表 为基准
  • 右表所有记录全部显示
  • 左表没有匹配 → 显示 NULL

语法

sql 复制代码
SELECT 字段 
FROM 表1 
RIGHT JOIN 表2 
ON 连接条件;

经典案例:查询没有学生的班级

sql 复制代码
SELECT c.* 
FROM student s 
RIGHT JOIN class c ON c.id = s.class_id 
WHERE s.id IS NULL;

结果:

sql 复制代码
3 | 前端001班

六、自连接(自己连接自己)

6.1 什么是自连接

同一张表 当作两张表来使用。必须给表起两个不同别名,否则报错:

sql 复制代码
Not unique table/alias

6.2 自连接使用场景

  • 行与行比较(成绩对比、上下级、树形结构)
  • 行转列
  • 同表内数据匹配

6.3 经典案例(PDF 原题)

需求:

查询 MySQL 成绩比 Java 成绩高 的学生信息、班级、两门课分数。

步骤:

  1. Java 课程 id = 1
  2. MySQL 课程 id = 3
  3. 同一个学生,比较两条成绩
sql 复制代码
SELECT 
  stu.name AS 姓名,
  c.name AS 班级,
  s1.score AS MySQL分数,
  s2.score AS Java分数
FROM
  score s1,
  score s2,
  course c1,
  course c2,
  student stu,
  class c
WHERE 
  s1.student_id = s2.student_id
  AND s1.course_id = c1.id
  AND s2.course_id = c2.id
  AND s1.score > s2.score
  AND c1.name = 'MySQL'
  AND c2.name = 'Java'
  AND stu.id = s1.student_id
  AND stu.class_id = c.id;

执行结果:

sql 复制代码
唐三藏 | Java001班 | 98.5 | 70.5
猪悟能 | Java001班 | 68   | 33

七、子查询(嵌套查询)

7.1 子查询定义

一个 SELECT 的结果 ,当作另一个 SELECT 的条件 。也叫嵌套查询

7.2 子查询分类

  1. 单行子查询
  2. 多行子查询
  3. 多列子查询
  4. FROM 子句中的子查询(临时表)

7.3 单行子查询

子查询只返回一行一列 。使用 = 比较。

案例:查询和 "不想毕业" 同班的同学

sql 复制代码
SELECT * FROM student 
WHERE class_id = (
  SELECT class_id FROM student 
  WHERE name='不想毕业'
);

7.4 多行子查询

子查询返回多行一列。必须使用:

  • IN
  • NOT IN
  • ANY
  • ALL

案例:查询 Java 或 MySQL 课程的成绩

sql 复制代码
SELECT * FROM score 
WHERE course_id IN (
  SELECT id FROM course 
  WHERE name='Java' OR name='MySQL'
);

7.5 多列子查询

返回多列数据,多字段匹配。

案例:查询重复录入的成绩

sql 复制代码
SELECT * FROM score 
WHERE (score, student_id, course_id) IN (
  SELECT score, student_id, course_id 
  FROM score 
  GROUP BY score, student_id, course_id 
  HAVING COUNT(0) > 1
);

7.6 FROM 子句中的子查询(临时表)

把子查询结果当作临时表使用。

案例:查询比 Java001 班平均分高的成绩

sql 复制代码
SELECT * FROM score s, 
(
  SELECT AVG(sc.score) score 
  FROM student s
  JOIN class c ON s.class_id = c.id
  JOIN score sc ON s.id = sc.student_id
  WHERE c.name = 'Java001班'
) tmp
WHERE s.score > tmp.score;

八、合并查询(UNION / UNION ALL)

8.1 作用

多个 SELECT 查询结果合并成一个结果集。

8.2 UNION

自动去重

sql 复制代码
SELECT * FROM student WHERE id < 3 
UNION 
SELECT * FROM student1;

8.3 UNION ALL

不去重,性能更高。

sql 复制代码
SELECT * FROM student WHERE id < 3 
UNION ALL 
SELECT * FROM student1;

九、插入查询结果(INSERT INTO ... SELECT)

9.1 作用

查询出来的数据,直接插入到另一张表。常用于:

  • 数据备份
  • 数据统计
  • 数据迁移

9.2 语法

sql 复制代码
INSERT INTO 表名 (字段1,字段2...) 
SELECT 字段1,字段2... FROM 源表;

9.3 案例(PDF 原题)

把 C++001 班的学生,复制到 student1 表:

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班';

十、全文超详细总结(面试 / 考试必背)

10.1 联合查询核心

  • 多表查询先做笛卡尔积
  • 再按连接条件过滤
  • 表越多性能越低

10.2 内连接

  • 只返回匹配数据
  • 关键字:JOIN / INNER JOIN
  • 最常用

10.3 外连接

  • 左连接:左表全显
  • 右连接:右表全显
  • 无匹配显示 NULL

10.4 自连接

  • 自己连自己
  • 必须起别名
  • 用于行比较、行转列

10.5 子查询

  • 一个 SELECT 嵌套另一个 SELECT
  • 支持单行、多行、多列、临时表

10.6 合并查询

  • UNION:去重
  • UNION ALL:不去重,更快

10.7 插入查询

  • INSERT INTO ... SELECT
  • 直接把查询结果插入表

总结

以上就是今天要讲的内容,本文简单记录了数据库学习内容,仅作为一份简单的笔记使用,大家根据注释理解,您的点赞关注收藏就是对小编最大的鼓励!

相关推荐
云飞云共享云桌面2 小时前
SolidWorks三维设计不用单独买电脑,1台服务器10个设计用
运维·服务器·数据库·3d·电脑
l1t2 小时前
DeepSeek总结的PAX:PostgreSQL存储引擎
数据库·postgresql
我不听你讲话2 小时前
PostgreSQL 日常维护核心内容总结
数据库·postgresql
倔强的石头1062 小时前
数据库行标识符机制探究:OID、ROWID与自增主键的实现与应用
数据库·oracle·kingbase
quintin-lee2 小时前
Postgres 内核:从入门到“入土” (三) —— Page 结构:数据是如何在磁盘上“躺平”的
c语言·数据库·postgresql·数据库架构
不愿透露姓名的大鹏3 小时前
MySQL Binlog配置优化全攻略
运维·服务器·数据库·mysql·adb
柒.梧.3 小时前
MySQL核心考点:存储引擎区别+视图详解
数据库·mysql·面试
电商API&Tina3 小时前
跨境电商如何接入1688官方寻源通接口?附接入流程
java·数据库·python·sql·oracle·json·php
明月_清风3 小时前
🚀 Flyway 存量数据库迁移:50张表一键导出清洗实战(附完整脚本)
数据库·后端