【MYSQL】MYSQL学习的一大重点:基本查询(下)

🎬 个人主页艾莉丝努力练剑
专栏传送门 :《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录
Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享

⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平


🎬 艾莉丝的简介:


文章目录

  • [1 ~> 数据更新操作(UPDATE)](#1 ~> 数据更新操作(UPDATE))
    • [1.1 基础语法与执行逻辑](#1.1 基础语法与执行逻辑)
    • [1.2 使用规范与风险管控](#1.2 使用规范与风险管控)
    • [1.3 典型应用场景](#1.3 典型应用场景)
      • [1.3.1 单条件单列更新](#1.3.1 单条件单列更新)
      • [1.3.2 单条件多列更新](#1.3.2 单条件多列更新)
      • [1.3.3 排序限量更新](#1.3.3 排序限量更新)
      • [1.3.4 全表更新(高危操作)](#1.3.4 全表更新(高危操作))
  • [2 ~> 数据删除操作(DELETE & TRUNCATE)](#2 ~> 数据删除操作(DELETE & TRUNCATE))
    • [2.1 DELETE 语句](#2.1 DELETE 语句)
      • [2.1.1 基础语法](#2.1.1 基础语法)
      • [2.1.2 条件删除](#2.1.2 条件删除)
      • [2.1.3 限量删除](#2.1.3 限量删除)
      • [2.1.4 全表删除特性](#2.1.4 全表删除特性)
    • [2.2 TRUNCATE 截断表](#2.2 TRUNCATE 截断表)
      • [2.2.1 语法与执行效果](#2.2.1 语法与执行效果)
      • [2.2.2 底层原理与特性](#2.2.2 底层原理与特性)
    • [2.3 DELETE 与 TRUNCATE 核心对比](#2.3 DELETE 与 TRUNCATE 核心对比)
  • [3 ~> 插入查询结果(INSERT ... SELECT)](#3 ~> 插入查询结果(INSERT ... SELECT))
    • [3.1 语法结构与适用场景](#3.1 语法结构与适用场景)
    • [3.2 表数据去重实战](#3.2 表数据去重实战)
      • [3.2.1 实现思路](#3.2.1 实现思路)
      • [3.2.2 执行步骤](#3.2.2 执行步骤)
      • [3.2.3 RENAME 原子性原理](#3.2.3 RENAME 原子性原理)
  • [4 ~> 聚合函数(聚合统计)](#4 ~> 聚合函数(聚合统计))
    • [4.1 核心作用](#4.1 核心作用)
    • [4.2 五大核心函数详解](#4.2 五大核心函数详解)
      • [4.2.1 COUNT ():统计行数](#4.2.1 COUNT ():统计行数)
      • [4.2.2 SUM ():数值求和](#4.2.2 SUM ():数值求和)
      • [4.2.3 AVG ():数值求平均](#4.2.3 AVG ():数值求平均)
      • [4.2.4 MAX () / MIN ():求极值](#4.2.4 MAX () / MIN ():求极值)
    • [4.3 使用约束与易错点](#4.3 使用约束与易错点)
  • [5 ~> 分组查询(GROUP BY)](#5 ~> 分组查询(GROUP BY))
    • [5.1 分组核心逻辑](#5.1 分组核心逻辑)
    • [5.2 分组语法](#5.2 分组语法)
      • [5.2.1 单字段分组](#5.2.1 单字段分组)
      • [5.2.2 多字段分组](#5.2.2 多字段分组)
    • [5.3 HAVING 分组后过滤](#5.3 HAVING 分组后过滤)
    • [5.4 WHERE 与 HAVING 的本质区别](#5.4 WHERE 与 HAVING 的本质区别)
    • [5.5 only_full_group_by 约束规则](#5.5 only_full_group_by 约束规则)
  • [6 ~> SQL 执行顺序与实战考点](#6 ~> SQL 执行顺序与实战考点)
    • [6.1 SQL 关键字执行优先级](#6.1 SQL 关键字执行优先级)
    • [6.2 高频面试考点](#6.2 高频面试考点)
    • [6.3 实战刷题推荐](#6.3 实战刷题推荐)
  • 结尾


1 ~> 数据更新操作(UPDATE)

1.1 基础语法与执行逻辑

UPDATE 属于 DML(数据操作语言),用于修改表中指定行的列值,执行逻辑为先按条件匹配行,再对匹配行执行列更新。 标准语法:

sql 复制代码
UPDATE table_name 
SET column = expr [, column = expr ...]
[WHERE ...] [ORDER BY ...] [LIMIT ...]
  • SET 子句:指定更新列与目标值,右侧支持常量、列运算表达式;MySQL 不支持 math += 30 这类自增简写,必须写作 math = math + 30
  • WHERE 子句:筛选待更新的行,是数据安全的核心屏障。
  • ORDER BY + LIMIT:对匹配结果排序后,仅更新前 N 行。

1.2 使用规范与风险管控

  1. 先查后改:执行 UPDATE 前,必须先用相同 WHERE 条件执行 SELECT,确认更新范围符合预期。
  2. 严禁无 WHERE 更新:缺失 WHERE 子句会对全表指定列执行更新,属于数据库高危操作,生产环境禁止手工执行。
  3. 权限隔离:生产库通常仅开放应用服务的 UPDATE 权限,禁止研发人员直连数据库执行手工数据修改。

1.3 典型应用场景

1.3.1 单条件单列更新

需求:将孙悟空同学的数学成绩变更为 80 分

sql 复制代码
-- 步骤1:查询验证目标数据
SELECT name, math FROM exam_result WHERE name = '孙悟空';

-- 步骤2:执行数据更新
UPDATE exam_result SET math = 80 WHERE name = '孙悟空';

-- 步骤3:验证更新结果
SELECT name, math FROM exam_result WHERE name = '孙悟空';

1.3.2 单条件多列更新

需求:将曹孟德同学的数学成绩改为 60 分,语文成绩改为 70 分

sql 复制代码
-- 多列更新用逗号分隔,一次性生效
UPDATE exam_result 
SET math = 60, chinese = 70 
WHERE name = '曹孟德';

1.3.3 排序限量更新

需求:将总成绩倒数前三的 3 位同学的数学成绩加上 30 分

sql 复制代码
-- 先查询确认倒数前三的名单
SELECT name, math, chinese + math + english AS 总分 
FROM exam_result
ORDER BY 总分 ASC LIMIT 3;

-- 按总分升序排序,取前3行执行更新
UPDATE exam_result 
SET math = math + 30
ORDER BY chinese + math + english ASC 
LIMIT 3;

注意:更新后学生总分排名可能发生变化,原倒数第三名可能脱离倒数区间。

1.3.4 全表更新(高危操作)

需求:将所有同学的语文成绩更新为原来的 2 倍

sql 复制代码
-- 无WHERE子句,全表所有行生效,生产环境必须经过审批与备份后方可执行
UPDATE exam_result SET chinese = chinese * 2;

2 ~> 数据删除操作(DELETE & TRUNCATE)

2.1 DELETE 语句

DELETE 用于删除表中的行数据,执行后仅删除数据,保留表结构。

2.1.1 基础语法

sql 复制代码
DELETE FROM table_name 
[WHERE ...] [ORDER BY ...] [LIMIT ...]
  • 同 UPDATE 一致,无 WHERE 子句将删除全表所有行数据。
  • 支持 ORDER BY 排序后,通过 LIMIT 删除指定数量的行。

2.1.2 条件删除

需求:删除孙悟空同学的考试成绩

sql 复制代码
-- 先验证目标行
SELECT * FROM exam_result WHERE name = '孙悟空';
-- 执行删除
DELETE FROM exam_result WHERE name = '孙悟空';

2.1.3 限量删除

需求:删除全班总分倒数第一的同学成绩

sql 复制代码
DELETE FROM exam_result 
ORDER BY chinese + math + english ASC 
LIMIT 1;

2.1.4 全表删除特性

  • 执行 DELETE FROM 表名; 会清空全表数据,但不会重置 AUTO_INCREMENT 自增计数器,后续新插入数据的 ID 会在旧最大值基础上继续递增。
  • DELETE 是行级操作,走事务流程,支持事务内回滚;会生成完整的 redo/undo 日志,数据可恢复。

2.2 TRUNCATE 截断表

TRUNCATE 属于 DDL(数据定义语言),用于快速清空整表数据。

2.2.1 语法与执行效果

sql 复制代码
TRUNCATE [TABLE] table_name;

执行效果:清空表中所有数据,保留表结构,同时重置 AUTO_INCREMENT 自增计数器。

2.2.2 底层原理与特性

  1. 操作粒度:只能对整表操作,无法像 DELETE 一样按条件删除部分数据。
  2. 执行效率:远高于 DELETE 全表;原理是直接释放表的数据页,而非逐行删除数据。
  3. 事务与回滚:不经过事务引擎的行级处理,无法通过事务回滚恢复数据。
  4. 日志特性【审计修正】:原文 "truncate 不记录日志" 表述不严谨。准确表述为:truncate 不产生逐行删除的 undo/redo 行级日志,但会将 DDL 操作记录到 binlog 中,因此主从复制架构下可正常同步。
  5. 自增特性:会重置 AUTO_INCREMENT 计数器为初始值,新插入数据 ID 从 1 开始计数。

2.3 DELETE 与 TRUNCATE 核心对比

对比维度 DELETE TRUNCATE
语句类型 DML 数据操作语言 DDL 数据定义语言
操作范围 支持 WHERE 条件删除部分行 只能清空整表
执行原理 逐行删除,记录行级日志 直接释放数据页,执行效率极高
自增计数器 不重置,保留原有计数 重置为初始值
事务回滚 支持事务内回滚 不支持事务回滚
触发器 会触发表的 DELETE 触发器 不会触发任何触发器

3 ~> 插入查询结果(INSERT ... SELECT)

3.1 语法结构与适用场景

将 SELECT 查询的结果集直接批量插入到目标表中,常用于数据迁移、表汇总、数据去重等场景。

sql 复制代码
INSERT INTO table_name [(column [, column ...])]
SELECT ...;
  • 要求 SELECT 结果的列数量、数据类型与目标表的插入列一一对应。
  • 支持全列插入(省略列名)与指定列插入。

3.2 表数据去重实战

需求:删除表中的重复记录,每组重复数据仅保留一份。

3.2.1 实现思路

当表无唯一主键、重复行完全一致时,无法直接通过 DELETE 删除部分重复行(删除会清除所有重复项)。因此采用 "建新表→插入去重数据→原子重命名切换" 的方案,实现无感知去重。

3.2.2 执行步骤

sql 复制代码
-- 1. 创建与原表结构完全一致的空表
CREATE TABLE no_duplicate_table LIKE duplicate_table;

-- 2. 将原表去重后的数据批量插入新表
INSERT INTO no_duplicate_table 
SELECT DISTINCT * FROM duplicate_table;

-- 3. 原子重命名:原表改名备份,新表改为原表名,一步完成切换
RENAME TABLE 
  duplicate_table TO old_duplicate_table,
  no_duplicate_table TO duplicate_table;

-- 4. 验证去重结果
SELECT * FROM duplicate_table;

3.2.3 RENAME 原子性原理

  • MySQL 的 RENAME TABLE 是原子操作,本质是修改文件系统中表文件的名称与 inode 映射关系,不涉及数据拷贝,执行速度极快(毫秒级)。
  • 业务无感知:切换过程中不会出现表不存在的中间状态,是生产环境数据表变更的标准方案。
  • 对应 Linux 底层:调用 rename 系统调用,仅修改目录项的文件名映射,不移动磁盘数据块。

4 ~> 聚合函数(聚合统计)

4.1 核心作用

聚合函数对一组行数据进行汇总计算,最终返回单个统计结果,是分组查询的基础能力。

4.2 五大核心函数详解

4.2.1 COUNT ():统计行数

语法:COUNT([DISTINCT] expr)

  • COUNT(*):统计结果集的总行数,不受 NULL 值影响,是最标准的统计写法。
  • COUNT(列名):统计指定列非 NULL 的行数,列值为 NULL 的行不计入统计。
  • COUNT(DISTINCT 列名):统计指定列去重后的非 NULL 行数。
  • COUNT(1):效果与COUNT(*)在 InnoDB 引擎下性能无显著差异。

示例:

sql 复制代码
-- 统计班级总人数
SELECT COUNT(*) AS 总人数 FROM exam_result;
-- 统计有数学成绩的学生数
SELECT COUNT(math) FROM exam_result;
-- 统计不重复的数学成绩数量
SELECT COUNT(DISTINCT math) FROM exam_result;

4.2.2 SUM ():数值求和

对数值列进行求和计算,非数值列无意义;无匹配行时返回 NULL。 示例:

sql 复制代码
-- 统计全班数学成绩总分
SELECT SUM(math) AS 数学总分 FROM exam_result;
-- 统计不及格学生的数学总分
SELECT SUM(math) FROM exam_result WHERE math < 60;

4.2.3 AVG ():数值求平均

对数值列计算平均值,自动忽略 NULL 值行。 示例:

sql 复制代码
-- 统计全班三科平均总分
SELECT AVG(chinese + math + english) AS 平均总分 FROM exam_result;

4.2.4 MAX () / MIN ():求极值

返回指定列中的最大值 / 最小值,非数值列无统计意义。 示例:

sql 复制代码
-- 查询英语最高分
SELECT MAX(english) FROM exam_result;
-- 查询70分以上的数学最低分
SELECT MIN(math) FROM exam_result WHERE math > 70;

4.3 使用约束与易错点

  1. 无 GROUP BY 时,聚合函数对整个结果集计算,SELECT 后只能跟随聚合函数,不能跟随普通列(only_full_group_by模式下会直接报错)。
  2. 聚合函数不能直接写在 WHERE 子句中(WHERE 执行顺序早于聚合计算),聚合结果的条件过滤必须使用 HAVING。

5 ~> 分组查询(GROUP BY)

5.1 分组核心逻辑

按照指定列的值,将整张表的数据划分为多个逻辑组,对每个组分别执行聚合统计,最终每组返回一条统计结果。

  • 核心价值:实现按维度统计,如 "每个部门的平均工资""每个岗位的人数"。
  • 理解模型:分组等价于将一张大表逻辑拆分为多张子表,每张子表独立执行聚合统计。

5.2 分组语法

5.2.1 单字段分组

需求:查询每个部门的平均工资和最高工资

sql 复制代码
SELECT deptno, AVG(sal) AS 平均工资, MAX(sal) AS 最高工资
FROM emp
GROUP BY deptno;

5.2.2 多字段分组

需求:查询每个部门下每种岗位的平均工资和最低工资

sql 复制代码
SELECT deptno, job, AVG(sal) AS 平均工资, MIN(sal) AS 最低工资
FROM emp
GROUP BY deptno, job;
  • 分组字段越多,分组粒度越细,最终结果的行数越多。

5.3 HAVING 分组后过滤

对分组聚合后的结果进行条件筛选,必须与 GROUP BY 配合使用。 需求:显示平均工资低于 2000 的部门和它的平均工资

sql 复制代码
SELECT deptno, AVG(sal) AS 平均工资
FROM emp
GROUP BY deptno
HAVING 平均工资 < 2000;

5.4 WHERE 与 HAVING 的本质区别

对比维度 WHERE HAVING
执行阶段 分组前过滤,作用于原始表行 分组后过滤,作用于聚合结果
过滤对象 原始行数据 分组后的统计结果
聚合函数 不能使用聚合函数作为条件 可以直接使用聚合结果作为筛选条件
执行顺序 先于 GROUP BY 执行 后于 GROUP BY 执行

核心结论:WHERE 过滤 "原始数据行",HAVING 过滤 "聚合统计结果",二者应用场景不同,无法完全互相替代。

5.5 only_full_group_by 约束规则

  • MySQL 默认开启 sql_mode=only_full_group_by 严格模式。
  • 规则:SELECT 子句中出现的列,必须是 GROUP BY 后的分组列,或者是聚合函数的计算结果。
  • 底层逻辑:非分组列在组内不唯一,无法确定返回组内哪一行的值,属于逻辑不严谨的写法。
  • 错误示例:SELECT ename, deptno, AVG(sal) FROM emp GROUP BY deptno; 会触发语法错误,因为ename既不是分组列也不是聚合结果。

6 ~> SQL 执行顺序与实战考点

6.1 SQL 关键字执行优先级

标准 SQL 的执行流程(优先级从高到低):

Plain 复制代码
FROM > ON > JOIN > WHERE > GROUP BY > WITH > HAVING > SELECT > DISTINCT > ORDER BY > LIMIT
  • 核心理解:先确定数据源(FROM/JOIN),再过滤无效行(WHERE),再分组聚合(GROUP BY/HAVING),再筛选输出列(SELECT),最后排序与分页(ORDER BY/LIMIT)。
  • 这也是 "WHERE 中不能用 SELECT 别名、不能用聚合函数,而 HAVING 可以用 SELECT 别名" 的根本原因。

6.2 高频面试考点

  1. DELETE 与 TRUNCATE 的核心区别
  2. WHERE 与 HAVING 的本质区别与应用场景
  3. GROUP BY 的执行逻辑与 only_full_group_by 约束
  4. 单条 SQL 的完整执行顺序
  5. 无主键表的数据去重实现方案

6.3 实战刷题推荐

  • 牛客 SQL 篇:批量插入数据、去重薪水查询、最晚入职员工、薪水涨幅统计、部门经理薪资、分组数目统计
  • LeetCode:重复邮箱、大的国家、第 N 高的薪水

结尾

uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ### 艾莉丝努力练剑 C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主 *** ** * ** *** 👀 【关注】 跟随我一起深耕技术领域,见证每一次成长。 ❤️ 【点赞】 让优质内容被更多人看见,让知识传递更有力量。 ⭐ 【收藏】 把核心知识点存好,在需要时随时查、随时用。 💬 【评论】 分享你的经验或疑问,评论区一起交流避坑! 不要忘记给博主"一键四连"哦! "今日练剑达成!" "技术之路难免有困惑,但同行的人会让前进更有方向。" |

结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主"一键四连"哦!

往期回顾

【MYSQL】MYSQL学习的一大重点:基本查询(上)

🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡 ૮₍ ˶ ˊ ᴥ ˋ˶₎ა

相关推荐
三少爷的鞋1 小时前
Android 中coroutineScope 和 supervisorScope 到底怎么选?先搞清楚 Exception 和 Result
android
晓梦林1 小时前
[极客大挑战 2019]Secret File学习笔记
笔记·学习
冰暮流星1 小时前
mysql之数据库创建,查询,删除,启用
数据库·mysql·oracle
GIS数据转换器1 小时前
智慧灌区管理平台
大数据·服务器·网络·数据库·人工智能·生活
STLearner2 小时前
ICML 2026 | LLM×Graph论文总结[2]【Graph4LLM,Graph4Agent,智能体记忆(Memory)
大数据·人工智能·python·深度学习·学习·机器学习·数据挖掘
其实防守也摸鱼3 小时前
KMP全栈开发:从Android到AI Agent的技术演进与实践
android·运维·网络·人工智能·学习·安全·macos
YM52e8 小时前
鸿蒙Flutter Padding内边距:EdgeInsets详解
android·学习·flutter·华为·harmonyos·鸿蒙
测试界的世清10 小时前
各大厂软件测试面试题+答案纯干货
面试·职场和发展
西安老张(AIGC&ComfyUI)10 小时前
第034章:ComfyUI&AIGC一阶段学习总结及下阶段学习安排
学习·aigc