《MySQL查询进阶:复合逻辑与多表关联的实战心法》

**前引:**复合查询的逻辑整合与多表查询的关联技巧,正是突破这一瓶颈的关键,也是从"会用MySQL"到"用好MySQL"的重要分水岭。本文将聚焦这两大核心知识点,结合实际场景拆解逻辑、梳理方法,帮助你夯实查询基础,在复杂数据需求中精准高效地提取信息。复合查询的逻辑整合与多表查询的关联技巧,正是突破这一瓶颈的关键,也是从"会用MySQL"到"用好MySQL"的重要分水岭。本文将聚焦这两大核心知识点,结合实际场景拆解逻辑、梳理方法,帮助你夯实查询基础,在复杂数据需求中精准高效地提取信息!

目录

语句顺序(必掌握)

(1)select

(2)from

(3)where

[(4)group by](#(4)group by)

(5)having

[(6)order by](#(6)order by)

(7)limit

(8)替换where:on...and

【一】复合查询实战

(1)实例1

(2)实例2

(3)实例3

(4)实例4

(5)实例5

(6)实例6

(7)实例7

【二】多表查询

(1)表的内连接

(2)表的外连接

(1)左外连接

(2)右外连接

【三】索引

(1)MySQL与磁盘

(2)三条共识

[(3)页目录 与 B+树](#(3)页目录 与 B+树)

(4)非/聚簇索引

(5)创建索引

(6)查询索引

(7)删除索引

(8)索引的创建原则


语句顺序(必掌握)

牢记下面关键字的书写顺序(非执行顺序):

select→from→where→group by→having→order by→limit

(1)select

作用:指定 "要显示哪些字段"

(2)from

作用:告诉 MySQL,你要查的数据来自哪个 / 哪些表

(3)where

作用:筛选 "满足条件的内容",一般搭配条件,如下

条件类型 符号 需求例子 SQL 写法
等于(精确匹配) = 查姓名是 "张三" 的学生 SELECT * FROM student WHERE name = '张三';
大于 / 小于 > / < 查分数>80 的成绩 SELECT * FROM score WHERE score > 80;
不等于 != 或 <> 查不是 "数学" 科目的成绩 SELECT * FROM score WHERE subject != '数学';
包含在列表里 IN 查 "语文" 或 "数学" 的成绩 SELECT * FROM score WHERE subject IN ('语文', '数学');
是空值(无数据) IS NULL 查缺考的成绩(分数为 null) SELECT * FROM score WHERE score IS NULL;
不是空值 IS NOT NULL 查有分数的成绩 SELECT * FROM score WHERE score IS NOT NULL;
(4)group by

作用:按 "某个字段分组",比如:成绩有三种,那么就有三组

注意:select中的非聚合字段必须全部出现在 group by 后面,比如:

cpp 复制代码
-- select后非聚合字段:user_id、order_status(都在group by里)
-- 聚合字段:sum(amount)(无需在group by里)
select 
  user_id,  -- 非聚合字段,在group by里
  order_status,  -- 非聚合字段,在group by里
  sum(amount) as total_amount  -- 聚合字段
from orders
group by user_id, order_status;  -- group by参数:两个非聚合字段
(5)having

作用: 过滤 "分组后的结果",where是分组前过滤,having是分组后过滤(比如数学低于30分)

(6)order by

作用:对数据进行排序(升序 / 降序)

(7)limit

作用:返回的行数控制,比如 limit 3:只显示3行

(8)替换where:on...and

好处:一行搞定 "连表 + 过滤";

  • ON :负责 "两张表怎么连"(必须写,比如学生表和成绩表靠 student.id = score.stu_id
  • AND:在连表的基础上,额外 "筛掉不需要的数据"(比如只看语文成绩、分数≥80)

【一】复合查询实战

我们采用下面这样的表来做练习:可以直接CV进数据库

表结构:

cpp 复制代码
CREATE TABLE EMP (
  deptno INT,
  ename VARCHAR(20),
  job VARCHAR(20),
  sal INT,
  comm INT NULL
);

表数据:

cpp 复制代码
INSERT INTO EMP (deptno, ename, job, sal, comm) VALUES
(10, 'King', 'MANAGER', 5000, 1000),
(20, 'Smith', 'CLERK', 800, NULL),
(20, 'Jones', 'MANAGER', 2975, 500),
(30, 'Blake', 'MANAGER', 2850, 800),
(30, 'Clark', 'CLERK', 2450, NULL),
(10, 'Scott', 'ANALYST', 3000, 600),
(20, 'Adams', 'CLERK', 1100, 200),
(30, 'Turner', 'SALESMAN', 1500, 300),
(10, 'Miller', 'CLERK', 1300, NULL),
(20, 'Ford', 'ANALYST', 3000, 700);
(1)实例1

查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J

先找到工资、岗位字段:

现在找高于500的、或者岗位为指定的信息:

再并列条件:姓名首字母为大写的J,即 % 模糊匹配

(2)实例2

按照部门号升序而雇员的工资降序排序

先找:部门号、工资、雇员名称字段

再进行指定内容的排序:部门号升序、工资降序

(3)实例3

使用年薪进行降序排序

先找到年薪字段:这里就是月薪*12

完成降序:

(4)实例4

显示工资最高的员工的名字和工作岗位

先找员工、工资、岗位字段:

找工资最高的员工:

(5)实例5

显示工资高于平均工资的员工信息

先找:工资字段(这里就不演示了!),然后计算平均工资,中间用 > 进行判断:

(6)实例6

显示每个部门的平均工资和最高工资

先找工资字段(不演示),然后 avg 计算平均工资,和 max 计算最高工资:

(7)实例7

显示每种岗位的雇员总数,平均工资,

需要用 group by按对应字段分组(select中的非聚合字段必须全部出现在 group by中)

先拿到每种岗位的雇员总数:

【二】多表查询

实际开发中往往数据来自不同的表,所以需要多表查询

现在存在如下的两张表:

from 后面可以跟多张表,它们的数据会进行逐个组合,称为笛卡儿积,例如:

笛卡尔积之后两张表变为一张表,逻辑不变,当做一张表来进行查询

现在我们对两张表进行笛卡尔积:可以看到数据非常的乱,现在进行筛选

如果 E 表的 empno 在 P 中也有,我们就输出出来:

需要注意:如果两张表有同样的字段,需要指定查询,否则 select 无法查找

比如:查找奖金系数大于1的员工(distinct 可以去重)

现在我们准备如下两张表进行练习:

复制代码
-- 创建学生表
CREATE TABLE student (
  id INT PRIMARY KEY,
  name VARCHAR(20) NOT NULL
);

-- 创建成绩表(科目限定3类,方便筛选)
CREATE TABLE score (
  id INT PRIMARY KEY,
  stu_id INT,
  subject VARCHAR(10) CHECK (subject IN ('语文', '数学', '英语')),
  score INT
);

-- 插入学生数据(4名学生,覆盖不同成绩情况)
INSERT INTO student VALUES 
(1, '张三'),  -- 语文+数学(2科有成绩)
(2, '李四'),  -- 语文(有分)+英语(缺考,分数null)
(3, '王五'),  -- 数学(有分)+语文/英语(无成绩)
(4, '赵六');  -- 三科均无成绩

-- 插入成绩数据(含缺考、无对应学生的成绩)
INSERT INTO score VALUES 
(1, 1, '语文', 88),
(2, 1, '数学', 95),
(3, 2, '语文', 76),
(4, 2, '英语', null),  -- 缺考,分数null
(5, 3, '数学', 69),
(6, 5, '英语', 82);  -- 无对应学生的成绩
(1)表的内连接

含义:内连接实际上就是利用where子句,对两种表形成的笛卡儿积进行筛选

(2)表的外连接

含义:表的外连接分为左外连接和内外连接

(1)左外连接

含义:左侧的表完全显示我们就说是左外连接

语法:

复制代码
select 字段名  from 表名1 left join 表名2 on 连接条件
(2)右外连接

含义:左侧的表完全显示我们就说是左外连接

语法:

复制代码
select 字段 from 表名1 right join 表名2  on 连接条件

【三】索引

我们直接上原理讲解,拒绝废话!索引3是什么需要一步步循序渐进:

索引的作用:

提高数据的检索速度,数据插入、更新、删除的速度(即非IO的效率)

(1)MySQL与磁盘

首先磁盘的工作方式我们是知道的:每个盘面被分为多个扇区,每个磁面的摆臂+磁头告诉摆动来寻找目标位置,读取时以"块"作为单位读取,"块"由许多个扇区组成,如下图:

假设现在有8亿条数据,一定会在磁盘占据许多个扇区,寻找一个文件即找到对应的扇区

随机访问:本次IO所给出的扇区地址和上次IO给出扇区地址不连续,这样的话磁头在两次IO操作 之间需要作比较大的移动动作才能重新开始读/写数据

连续访问:如果当次IO给出的扇区地址与上次IO结束的扇区地址是连续的,那磁头就能很快的开 始这次 IO操作,这样的多个IO操作称为连续访问

MySQL为了提高数据的IO效率,和磁盘进行数据交互的基本单位是 16KB(4*4)

该数据单元,被称为 page(解决多次与磁盘IO问题)

(2)三条共识

(1)MySQL中的数据文件以page为单位保存在磁盘中的

(2)为了更好的进行上面的操作, MySQL 服务器在内存中运行的时候,在服务器内部,就申请 了被称为 Buffer Pool 的的大内存空间,来进行各种缓存

其实就是很大的内存空间,来和磁盘数据进行IO交互

(3)数据库文件肯定不止有一个page大小,那么管理多个page就需要组织起来:

Buffer Pool 空间大就可以随便放page吗?如何定位某个数据在哪个page?线性查找?

(3)页目录 与 B+树

页目录即根据目标唯一的主键进行区域划分:快速定位某个章节、页

例如:书的目录

页目录的查找效率提升:

如果找id为5的数据,从原来的线性查找5次,变成查找3次左右,数据越多,指数降低的越明显

那么如果数据足够多?所建立的目录也越多,趋近线性查找?

解决方法:我们也可以给目录再建立目录,例如:

目录页的本质也是页,普通页中存的数据是用户数据,而目录页中存的数据是普通页的地址

为何不是红黑树、哈希结构?红黑属于二叉树,比B+树更高,哈希也只能从上往下查找

https://www.cs.usfca.edu/~galles/visualization/Algorithms.html(可点击前往数据结构演示)

为什么不是B树?而是B+树?B+树的底部是相连的,意味临近数据可以直接左右查找

B树:

B+树:

**索引定义:**数据库实现快速查询而采用的数据结构(B+树)

(4)非/聚簇索引

聚簇索引:将用户数据与索引数据放在一起索引方案,例如:

非聚簇索引:将用户数据与索引数据不放在一起索引方案,例如:

(5)创建索引

主键索引:

唯一键索引:

普通索引创建:

(6)查询索引
(7)删除索引
(8)索引的创建原则
相关推荐
June`2 小时前
mini-redis项目之Resp协议
数据库·redis
lhbian2 小时前
redis分页查询
数据库·redis·缓存
顶点多余2 小时前
Mysql 基本查询详解
数据库·mysql
X-⃢_⃢-X2 小时前
八、Redis之BigKey
数据库·redis·缓存
~莫子2 小时前
Redis
数据库·redis·缓存
历程里程碑2 小时前
36 Linux线程池实战:日志与策略模式解析
开发语言·数据结构·数据库·c++·算法·leetcode·哈希算法
颜颜yan_2 小时前
从千毫秒到亚毫秒:连接条件下推如何让复杂 SQL 飞起来
数据库·sql
ChaITSimpleLove2 小时前
如何查看系统中 PostgreSQL 数据库的进程(postgres)运行状态?
数据库·postgresql·查看pgsql运行状态·pgsql进程运行状态·postgres 进程·tree 树形结构
ChaITSimpleLove2 小时前
PostgreSQL 部署与运维常用命令详解
运维·数据库·postgresql·部署·命令解析