六.MySQL增删查改
CRUD : Create(创建), Retrieve(读取),Update(更新),Delete(删除)
一.增 insert
1.单行数据 + 全列插入
语法特点:不指定字段名,按表结构字段顺序依次提供所有值。
注意:字段顺序必须与表定义一致。
into可省略 每个字段都填入值时可以省略values前面的()
2.多行插入 + 指定列插入
优势:插入效率更高,推荐写法。
注意:指定列名后,后面所有的 value_list 数量和顺序必须一致。
多行插入时 用 ,号隔开
3.插入失败则更新 on duplicate key update
我们知道由于 主键 或者 唯一键 对应的值已经存在会导致插入失败 冲突,但我们想更新这行的内容怎么办?
on duplicate key update 字段=新值 ...
on duplicate key update表示如果前面的行插入失败了,说明和表中的某行冲突了,就把冲突的行对应字段值换成后面新值的行,当然新行不能和原表中的行冲突。
insert语句执行结果返回的 受影响行数
1.没有冲突行 插入成功 受影响1行
2.冲突 但值一致不需要改 受影响0行
3.冲突 值不一致 删除冲突行 换新行 受影响2行
情况 结果说明 没有冲突 正常插入 返回 1 行受影响 主键/唯一键冲突,值不变 不插入,也不更新,返回 0 行受影响 主键/唯一键冲突,值有更新 冲突行被更新,返回 2 行受影响 UPDATE 中再次引起其他唯一键冲突 会报错,事务中止
4.替换 replace into
replace into替换和insert into on duplicate key update更新区别在于,出现冲突时
1.replace into是先删除 再插入新的行
2.insert into duplicate key update只有修改主键时才会删除 再插入新行,不修改主键就只更新对应字段值就可以了。简单来说就是,不修改主键 就可以在原行中进行更新。
最明显的就是插入一个完全一样的行 冲突时,replace into还是会先删除再插入,执行完返回受影响的行数为2
而duplicate并不会进行删除修改,返回受影响的行数为0
replace into:无脑删+插,哪怕值一样也删你;
insert into on duplicate key update:只改有变的,不动就不碰你,改主键才会删+插。
维度 | replace into | insert into on duplicate key update |
---|---|---|
基本功能 | 插入数据,如主键/唯一键冲突,则先删除旧行再插入新行 | 插入数据,如冲突,则直接更新已存在的冲突行 |
是否保留原主键(或 auto_increment) | ❌ 不保留,重新分配主键 ID(除非显式写入) | ✅ 保留原主键 |
是否真执行了 删除+插入 | ✅ 是(底层执行删除再插入) | ❌ 否(除非你显式更新主键字段,此时也会变成 删除+插入) |
是否支持部分字段更新 | ❌ 不支持,必须完整提供所有列(没有 UPDATE 子句) | ✅ 支持,只需要指定更新哪些列 |
使用场景推荐 | ✅ 推荐用于缓存表、日志表、临时去重 | ✅ 推荐用于需要维护业务数据一致性、幂等更新操作 |
性能影响 | ❌ 高(因为删除+插入) | ✅ 更好(原地更新) |
影响行数(无冲突) | 插入成功:1 行 | 插入成功:1 行 |
影响行数(冲突 + 值未变) | 删除 + 插入同值:2 行 | UPDATE 无变化:0 行 |
影响行数(冲突 + 值有变化) | 删除 + 插入不同值:2 行 | UPDATE 成功:2 行 |
二.查 select
1.全列查询 select * from
2.指定列查询select 字段,字段 from
查询多个字段用 ,号隔开
3.查询字段为表达式 select 字段 from
1.常量表达式(无字段):
所有行都会显示一个值为 10 的列。
2.单字段表达式:
每行qq加 1 后展示。
3.多字段表达式(计算总分):
4.为查询结果指定别名
5.查询结果去重 select distinct 字段 from
去除查询结果中的重复值;
可用于单列或多列组合去重:
条件筛选where
用于限定查询结果,只返回满足指定条件的记录。
返回满足条件的行
一、比较运算符
运算符 | 含义 | 示例 |
---|---|---|
> / < | 大于 / 小于 | where score > 60 |
>= / <= | 大于等于 / 小于等于 | where score <= 90 |
= | 等于(不推荐用于 null) | where name = '张三' |
<=> | 安全等于(支持 null 比较) | where a <=> null |
!= / <> | 不等于 | where name != '张三' |
between a and b | 范围闭区间 [a, b] | where score between 80 and 90 |
in (...) | 是否在某几个值中 | where name in ('张三', '李四') |
is null | 是否为空 | where qq is null |
is not null | 是否非空 | where qq is not null |
like | 模糊匹配 % 任意字符 _ 一个字符 | where name like '张%' |
二、逻辑运算符
运算符 | 含义 | 示例 |
---|---|---|
and | 所有条件都成立,结果为 true | where math > 70 and english > 70 |
or | 任一条件成立,结果为 true | where name = '张三' or name = '李四' |
not | 对结果取反 | where not (english > 60) |
查询操作练习
1.英语不及格的同学
2.语文成绩在 80~90 分之间的同学
3.数学成绩为 58、59、98 或 99 的同学
4.姓“孙”的同学
条件 %:name LIKE '孙%' → 任意“孙某某”
条件 _:name LIKE '孙_' → 精确“孙某”两个字的姓名
5.语文成绩 > 英语成绩的同学
where chinese>english;
6.总分 < 200 的同学
为什么where用别名查询不行呢?
因为select语句的执行顺序是1.form确定数据来源 2.where 筛选条件 3.select计数表达式 生成结果。
在2.where执行时,select中的别名(如 sum)还没被定义出来,自然不能在 where中使用!
7.语文成绩 > 80 并且不姓孙的同学
8.孙某同学,否则要求总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80
9.NULL 的查询
结果排序 order by 字段 asc|desc
关键词 含义 默认 asd 升序(从小到大) ✅ 是默认排序 desc 降序(从大到小) ❌ 需手动指定 多列排序 先按前列,再按次列(类似 Excel 多重排序) 支持
排序练习
1.同学及数学成绩,按数学成绩升序显示
2.NULL被视为最小值
3.查询同学各门成绩,依次按 数学降序,英语升序,语文升序的方式显示
4.查询同学及总分,由高到低
为什么这里 order by 别名 就能用别名排序了呢?
因为我们可以说先筛选出符合条件的行再进行排序的 ,也就是order by是select执行完以后排序的,total别名已经存在了。
5.查询姓孙的同学或者姓曹的同学数学成绩,结果按数学成绩由高到低显示
筛选分页结果 limit
写法 含义 示例 limit n
取前 n
条记录limit 3
limit s, n
从下标为s的行开始取 n
条limit 0,3
limit n offset s
同上 limit 3 offset 0
![]()
分页查询
三.改 update set
update 表名 set 列1 = 新值1, 列2 = 新值2, ... where条件;
1 将孙悟空同学的数学成绩变更为 80 分
2.将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分
3.将总成绩倒数前三的 3 位同学的数学成绩加上 30 分
1.总成绩升序 limit 3 取3名 order by 总成绩 limit 3;
2.update
4.将所有同学的语文成绩更新为原来的 2 倍 慎用
四.删 delete from / truncate
1.删除数据delete from
delete from 表 where ; 删除满足条件的数据
delete from 表;删除整张表的数据
2.截断表 truncate 表
delete from 和 truncate 有什么区别?
1.delete from 表 where; 可以选择删除一部分的数据。但truncate只能删除整表的数据
2.delete属于事务操作 删除数据后可以撤回,truncate非事务操作 删除数据没有记录 不能撤回 执行更快。
3.delete 删除不会重置auto_increment表的自增计数器,而truncate会重置
delete
truncate
比较项 DELETE
TRUNCATE
删除范围 可通过 WHERE
删除部分数据只能整表删除,不支持 WHERE
是否支持事务 ✅ 支持(InnoDB引擎下可 ROLLBACK
回滚)❌ 不支持事务,操作不可撤回 是否可撤回(回滚) ✅ 可撤回 ❌ 不可撤回 操作类型 DML(数据操作语言) DDL(数据定义语言) 删除速度 较慢,逐行删除 很快,相当于重建表结构 影响自增计数器 ❌ 不重置 AUTO_INCREMENT
✅ 会重置,自增从 1 开始 是否记录 binlog ✅ 会记录 ✅ 会记录(以 DROP 重建方式记录) 触发器(Trigger)支持 ✅ 支持触发器 ❌ 不触发触发器 安全性 相对安全,可控 风险较大,执行立即生效,无法恢复 delete:精确、慢、安全,适合删除部分数据;
truncate:快速、粗暴、不可回滚,适合清空整表。
插入查询结果 (对表中数据去重)
这个表中有重复的数据 我们想对表中数据进行去重怎么操作?
1.创建一个结构相同的空表
2.插入 去重查询的结果到空表
3.最后让插入去重数据的表 改为原表名字
1.创建空白表 no_duplicate_table(结构相同)
create table no_duplicate_table like duplicate_table;
2.插入去重后的数据
insert into no_duplicate_table select distinct * from duplicate_table;
3.用rename table更改表名字
rename table duplicate_table to old_duplicate_table,no_duplicate_table to duplicate_table;
为什么通过rename table替换表名的方式进行操作?
原子操作 安全,中间处理的、转换的、过滤的所有数据,在 rename 这一刻,全部打包替换上去,一键生效,没有任何不一致或过渡状态。
聚合函数
函数 | 说明 | 示例 | 特点 |
---|---|---|---|
count(*) | 返回记录总数(包括 null) | select count(*) from students; | 最常用,效率高 |
count(expr) | 返回非 null 值的数量 | select count(qq) from students; | null 不计入 |
count(distinct expr) | 返回去重后非 null 的数量 | select count(distinct math) from exam_result; | 可去重 |
sum(expr) | 求和(数值型) | select sum(math) from exam_result; | null 忽略,全部 null 则返回 null |
avg(expr) | 平均值(数值型) | select avg(math) from exam_result; | null 忽略 |
max(expr) | 最大值 | select max(english) from exam_result; | 支持数值/字符串 |
min(expr) | 最小值 | select min(math) from exam_result where math > 70; | 支持数值/字符串 |
聚合函数特点
特点 | 说明 |
---|---|
只能出现在 select 或 having 子句中 | 不能直接在 where 里用 |
可配合 group by 分组使用 | 每组单独汇总,常见于报表分析 |
忽略 null (部分函数) | 如 sum() , avg() ,会跳过 null 值 |
1. 统计班级共有多少同学
2.统计数学成绩总分
3.统计平均总分
4.返回英语最高分
5.返回 > 90 分以上的数学最低分
分组统计group by
select 语句的执行流程:
where先筛选原数据 group by再进行分组(把一整个表分为多个)having 对分组后的结果再进行筛选 select选择要输出的内容 order by对输出内容进行排序 最后limit控制输出的数量
where: 对 原始数据进行筛选 不能用聚合函数
步骤 子句 作用说明 1️⃣ from
读取数据表,形成数据源 2️⃣ where
对原始数据进行行过滤(不能用聚合函数) 3️⃣ group by
将数据分组 4️⃣ having
对分组后的聚合结果进行组过滤 5️⃣ select
选择需要输出的列、表达式、聚合函数 6️⃣ order by
对最终结果进行排序 7️⃣ limit
限制输出记录条数(分页常用)
having:对 分组聚合的结果进行筛选 可以用聚合函数
1.显示每个部门的平均工资和最高工资
avg()平均 max()最高 group by 部门
select deptno,avg(sal) 平均,max(sal)最大 from EMP group by deptno;
2.显示每个部门的每种岗位的平均工资和最低工资
group by 部门,岗位;可以理解为先以部门进行分组,再以岗位进行分组。
select 里字段,只有两种能出现:
select deptno,job,avg(sal) 平均,min(sal)最小 from EMP group by deptno,job;
一个是聚合函数,一个是 group by 里的字段。
因为SQL 是基于分组后的“每一组”来生成结果行的,必须是一组中共同的东西
3.显示平均工资低于2000的部门和它的平均工资
1.group by以部门分组 avg算出平均薪资 2.having再对分完组的结果进行筛选
select deptno,avg(sal) 平均 from EMP group by deptno having 平均<2000;
4.除去SMITH员工 显示平均工资低于2000的部门和它的平均工资
not in(...)不在里面