MySQL 增删改查(CRUD)完全指南:从入门到面试

文章目录

    • [1. 引言](#1. 引言)
    • [2. 准备工作:创建学生表](#2. 准备工作:创建学生表)
    • [3. create:插入数据](#3. create:插入数据)
      • [3.1 单行数据 + 全列插入](#3.1 单行数据 + 全列插入)
      • [3.2 多行数据 + 指定列插入](#3.2 多行数据 + 指定列插入)
      • [3.3 插入否则更新(on duplicate key update)](#3.3 插入否则更新(on duplicate key update))
      • [3.4 替换(replace)](#3.4 替换(replace))
      • [3.5 replace 与 on duplicate key update 的区别](#3.5 replace 与 on duplicate key update 的区别)
    • [4. retrieve:查询数据](#4. retrieve:查询数据)
      • [4.1 创建成绩表](#4.1 创建成绩表)
      • [4.2 select 列](#4.2 select 列)
        • [4.2.1 全列查询](#4.2.1 全列查询)
        • [4.2.2 指定列查询](#4.2.2 指定列查询)
        • [4.2.3 查询字段为表达式](#4.2.3 查询字段为表达式)
        • [4.2.4 为查询结果指定别名](#4.2.4 为查询结果指定别名)
        • [4.2.5 结果去重](#4.2.5 结果去重)
      • [4.3 where 条件](#4.3 where 条件)
        • [4.3.1 比较运算符](#4.3.1 比较运算符)
        • [4.3.2 逻辑运算符](#4.3.2 逻辑运算符)
        • [4.3.3 实战案例](#4.3.3 实战案例)
      • [4.4 结果排序(order by)](#4.4 结果排序(order by))
      • [4.5 筛选分页结果(LIMIT)](#4.5 筛选分页结果(LIMIT))
    • [5. update:更新数据](#5. update:更新数据)
      • [5.1 将孙悟空同学的数学成绩变更为 80 分](#5.1 将孙悟空同学的数学成绩变更为 80 分)
      • [5.2 将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分](#5.2 将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分)
      • [5.3 将总成绩倒数前三的 3 位同学的数学成绩加上 30 分](#5.3 将总成绩倒数前三的 3 位同学的数学成绩加上 30 分)
      • [5.4 将所有同学的语文成绩更新为原来的 2 倍](#5.4 将所有同学的语文成绩更新为原来的 2 倍)
    • [6. delete:删除数据](#6. delete:删除数据)
      • [6.1 删除数据](#6.1 删除数据)
      • [6.2 删除整张表数据](#6.2 删除整张表数据)
      • [6.3 截断表(truncate)](#6.3 截断表(truncate))
    • [7. 插入查询结果](#7. 插入查询结果)
    • [8. 聚合函数](#8. 聚合函数)
      • [8.1 统计班级共有多少同学](#8.1 统计班级共有多少同学)
      • [8.2 统计班级收集的 qq 号有多少](#8.2 统计班级收集的 qq 号有多少)
      • [8.3 统计本次考试的数学成绩分数个数](#8.3 统计本次考试的数学成绩分数个数)

本文面向 MySQL 初学者,系统讲解数据库表的增删改查(CRUD)操作。从创建学生表开始,逐步演示 insert、select、update、delete 四大核心语句的语法与实战案例,并深入对比 replace 与 on duplicate key update 的区别,同时涵盖注意事项与常见面试题,助你从零掌握 MySQL 数据操作的核心技能。

1. 引言

在数据库开发中,对表的增删改查(CRUD)是最基础也是最重要的操作。crud 是 create(创建)、retrieve(读取)、update(更新)、delete(删除)四个单词的缩写,分别对应 SQL 中的 insert、select、update、delete 语句。

本文将从零开始,带你系统掌握 MySQL 的增删改查操作。你将学会如何创建表、插入数据、查询数据、更新数据以及删除数据,并通过大量实战案例理解 where 条件、排序、分页、聚合函数等核心知识点,同时掌握 replace 与 on duplicate key update 的区别,为面试和实际开发打下坚实基础。

2. 准备工作:创建学生表

在开始增删改查之前,我们先创建一张学生表作为演示基础:

sql 复制代码
-- 创建一张学生表
create table students (
    id int unsigned primary key auto_increment,
    sn int not null unique comment '学号',
    name varchar(20) not null,
    qq varchar(20)
);

这张表包含四个字段:

  • id:主键,自增,无符号整数
  • sn:学号,非空且唯一
  • name:姓名,非空
  • qq:QQ 号,可空

3. create:插入数据

3.1 单行数据 + 全列插入

sql 复制代码
insert into students values (101, 10001, '孙悟空', '11111');

执行结果:

复制代码
query ok, 1 row affected (0.02 sec)

3.2 多行数据 + 指定列插入

sql 复制代码
insert into students (id, sn, name) values
    (102, 20001, '曹孟德'),
    (103, 20002, '孙仲谋');

执行结果:

复制代码
Query OK, 2 rows affected (0.02 sec)
Records: 2  Duplicates: 0  Warnings: 0

注意 :value_list 的数量必须和指定列的数量及顺序一致。插入时也可以不指定 id,MySQL 会使用默认值进行自增。

3.3 插入否则更新(on duplicate key update)

当主键或唯一键对应的值已经存在而导致插入失败时,可以选择性地进行同步更新操作:

sql 复制代码
insert into students (id, sn, name) values (100, 10010, '唐大师')
    on duplicate key update sn = 10010, name = '唐大师';

执行结果:

复制代码
query ok, 2 rows affected (0.47 sec)

影响行数说明:

  • 0 row affected:表中有冲突数据,但冲突数据的值和 update 的值相等
  • 1 row affected:表中没有冲突数据,数据被插入
  • 2 row affected:表中有冲突数据,并且数据已经被更新

可以通过 MySQL 函数获取受影响的数据行数:

sql 复制代码
select row_count();

3.4 替换(replace)

replace 的机制是:主键或唯一键没有冲突则直接插入;如果冲突,则删除后再插入。

sql 复制代码
replace into students (sn, name) values (20001, '曹阿瞒');

执行结果:

复制代码
query ok, 2 rows affected (0.00 sec)

影响行数说明:

  • 1 row affected:表中没有冲突数据,数据被插入
  • 2 row affected:表中有冲突数据,删除后重新插入

3.5 replace 与 on duplicate key update 的区别

replace 和 on duplicate key update 都用于处理主键或唯一键冲突,但底层机制和适用场景有明显差异:

对比维度 replace into on duplicate key update
冲突处理机制 先删除冲突行,再插入新行 直接对冲突行执行 update 更新
是否删除原行 是,先 delete 再 insert 否,仅更新指定列
未指定列的处理 未指定的列会被重置为默认值 未指定的列保持原值不变
自增 id 变化 会重新分配新的自增 id 自增 id 保持不变
触发器行为 会触发 delete 和 insert 触发器 会触发 update 触发器
影响行数 冲突时返回 2(删除 1 行 + 插入 1 行) 冲突时返回 2(更新 1 行)
适用场景 整行替换,不关心其他列的原值 只更新部分列,保留其他列原值

核心区别示例:

假设 students 表中已存在 sn = 20001 的记录,且该行 name 为 '曹孟德'、qq 为 '12345':

sql 复制代码
-- 使用 replace:qq 列会被重置为默认值(null)
replace into students (sn, name) values (20001, '曹阿瞒');
-- 结果:sn = 20001, name = '曹阿瞒', qq = null

-- 使用 on duplicate key update:qq 列保持原值不变
insert into students (sn, name) values (20001, '曹阿瞒')
    on duplicate key update name = '曹阿瞒';
-- 结果:sn = 20001, name = '曹阿瞒', qq = '12345'

选择建议:

  • 需要整行替换 、不关心其他列原值时,用 replace into
  • 需要保留其他列原值 、只更新部分列时,用 on duplicate key update
  • 涉及外键约束时慎用 replace,因为先删后插可能触发外键级联删除

4. retrieve:查询数据

4.1 创建成绩表

sql 复制代码
create table exam_result (
    id int unsigned primary key auto_increment,
    name varchar(20) not null comment '同学姓名',
    chinese float default 0.0 comment '语文成绩',
    math float default 0.0 comment '数学成绩',
    english float default 0.0 comment '英语成绩'
);

-- 插入测试数据
insert into exam_result (name, chinese, math, english) values
    ('唐三藏', 67, 98, 56),
    ('孙悟空', 87, 78, 77),
    ('猪悟能', 88, 98, 90),
    ('曹孟德', 82, 84, 67),
    ('刘玄德', 55, 85, 45),
    ('孙权', 70, 73, 78),
    ('宋公明', 75, 65, 30);

4.2 select 列

4.2.1 全列查询
sql 复制代码
select * from exam_result;

注意 :通常情况下不建议使用 * 进行全列查询:

  1. 查询的列越多,需要传输的数据量越大
  2. 可能会影响到索引的使用
4.2.2 指定列查询
sql 复制代码
select id, name, english from exam_result;

指定列的顺序不需要按定义表的顺序来。

4.2.3 查询字段为表达式
sql 复制代码
-- 表达式不包含字段
select id, name, 10 from exam_result;

-- 表达式包含一个字段
select id, name, english + 10 from exam_result;

-- 表达式包含多个字段
select id, name, chinese + math + english from exam_result;
4.2.4 为查询结果指定别名
sql 复制代码
select id, name, chinese + math + english 总分 from exam_result;
4.2.5 结果去重
sql 复制代码
-- 98 分重复了
select math from exam_result;

-- 去重结果
select distinct math from exam_result;

4.3 where 条件

4.3.1 比较运算符
运算符 说明
>, >=, <, <= 大于,大于等于,小于,小于等于
= 等于,null 不安全,例如 null = null 的结果是 null
<=> 等于,null 安全,例如 null <=> null 的结果是 true(1)
!=, <> 不等于
between a0 and a1 范围匹配,a0, a1,如果 a0 <= value <= a1,返回 true(1)
in (option, ...) 如果是 option 中的任意一个,返回 true(1)
is null 是 null
is not null 不是 NULL
like 模糊匹配。% 表示任意多个(包括 0 个)任意字符;_ 表示任意一个字符
4.3.2 逻辑运算符
运算符 说明
and 多个条件必须都为 true(1),结果才是 true(1)
or 任意一个条件为 true(1),结果为 true(1)
not 条件为 true(1),结果为 false(0)
4.3.3 实战案例

英语不及格的同学及英语成绩(< 60):

sql 复制代码
select name, english from exam_result where english < 60;

语文成绩在 80, 90 分的同学及语文成绩:

sql 复制代码
-- 使用 and 进行条件连接
select name, chinese from exam_result where chinese >= 80 and chinese <= 90;

-- 使用 between ... and ... 条件
select name, chinese from exam_result where chinese between 80 and 90;

数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩:

sql 复制代码
-- 使用 or 进行条件连接
select name, math from exam_result
 where math = 58
 or math = 59
 or math = 98
 or math = 99;

-- 使用 in 条件
select name, math from exam_result where math in (58, 59, 98, 99);

姓孙的同学及孙某同学:

sql 复制代码
-- % 匹配任意多个(包括 0 个)任意字符
select name from exam_result where name like '孙%';

-- _ 匹配严格的一个任意字符
select name from exam_result where name like '孙_';

语文成绩好于英语成绩的同学:

sql 复制代码
select name, chinese, english from exam_result where chinese > english;

总分在 200 分以下的同学:

sql 复制代码
-- 别名不能用在 where 条件中
select name, chinese + math + english 总分 from exam_result
 where chinese + math + english < 200;

语文成绩 > 80 并且不姓孙的同学:

sql 复制代码
select name, chinese from exam_result
 where chinese > 80 and name not like '孙%';

孙某同学,否则要求总成绩 > 200 并且语文成绩 < 数学成绩并且英语成绩 > 80:

sql 复制代码
select name, chinese, math, english, chinese + math + english 总分
from exam_result
where name like '孙_' or (
    chinese + math + english > 200 and chinese < math and english > 80
);

NULL 的查询:

sql 复制代码
-- 查询 qq 号已知的同学姓名
select name, qq from students where qq is not null;

-- null 和 null 的比较,= 和 <=> 的区别
select null = null, null = 1, null = 0;
select null <=> null, null <=> 1, null <=> 0;

4.4 结果排序(order by)

语法:

sql 复制代码
select ... from table_name [where ...]
 order by column [asc|desc], [...];
  • asc 为升序(从小到大)
  • desc 为降序(从大到小)
  • 默认为 asc

注意 :没有 order by 子句的查询,返回的顺序是未定义的,永远不要依赖这个顺序。

同学及数学成绩,按数学成绩升序显示:

sql 复制代码
select name, math from exam_result order by math;

同学及 qq 号,按 qq 号排序显示:

sql 复制代码
-- null 视为比任何值都小,升序出现在最上面
select name, qq from students order by qq;

-- null 视为比任何值都小,降序出现在最下面
select name, qq from students order by qq desc;

查询同学各门成绩,依次按数学降序,英语升序,语文升序的方式显示:

sql 复制代码
-- 多字段排序,排序优先级随书写顺序
select name, math, english, chinese from exam_result
 order by math desc, english, chinese;

按总分降序显示:

sql 复制代码
-- 别名可以在 order by 中使用
select name, chinese + math + english 总分 from exam_result
 order by 总分 desc;

查询姓孙的同学或者姓曹的同学数学成绩,结果按数学成绩由高到低显示:

sql 复制代码
select name, math from exam_result
 where name like '孙%' or name like '曹%'
 order by math desc;

4.5 筛选分页结果(LIMIT)

语法:

sql 复制代码
-- 起始下标为 0
-- 从 s 开始,筛选 n 条结果
select ... from table_name [where ...] [order by ...] limit s, n;

-- 从 0 开始,筛选 n 条结果
select ... from table_name [where ...] [order by ...] limit n;

-- 从 s 开始,筛选 n 条结果,比第二种用法更明确,建议使用
select ... from table_name [where ...] [order by ...] limit n offset s;

建议 :对未知表进行查询时,最好加一条 limit 1,避免因为表中数据过大,查询全表数据导致数据库卡死。

按 id 进行分页,每页 3 条记录,分别显示第 1、2、3 页:

sql 复制代码
-- 第 1 页
select id, name, math, english, chinese from exam_result
 order by id limit 3 offset 0;

-- 第 2 页
select id, name, math, english, chinese from exam_result
 order by id limit 3 offset 3;

-- 第 3 页,如果结果不足 3 个,不会有影响
select id, name, math, english, chinese from exam_result
 order by id limit 3 offset 6;

5. update:更新数据

语法:

sql 复制代码
update table_name set column = expr [, column = expr ...]
 [where ...] [order by ...] [limit ...]

5.1 将孙悟空同学的数学成绩变更为 80 分

sql 复制代码
-- 查看原数据
SELECT name, math FROM exam_result WHERE name = '孙悟空';

-- 数据更新
update exam_result set math = 80 where name = '孙悟空';

-- 查看更新后数据
SELECT name, math FROM exam_result WHERE name = '孙悟空';

5.2 将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分

sql 复制代码
-- 一次更新多个列
update exam_result set math = 60, chinese = 70 where name = '曹孟德';

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

sql 复制代码
-- 查看原数据(别名可以在 ORDER BY 中使用)
select name, math, chinese + math + english 总分 from exam_result
 order by 总分 limit 3;

-- 数据更新,不支持 math += 30 这种语法
update exam_result set math = math + 30
 order by chinese + math + english limit 3;

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

sql 复制代码
-- 没有 WHERE 子句,则更新全表
update exam_result set chinese = chinese * 2;

注意:更新全表的语句慎用!

6. delete:删除数据

6.1 删除数据

语法:

sql 复制代码
delete from table_name [where ...] [order by ...] [limit ...]

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

sql 复制代码
delete from exam_result where name = '孙悟空';

6.2 删除整张表数据

sql 复制代码
-- 准备测试表
create table for_delete (
    id int primary key auto_increment,
    name varchar(20)
);

-- 插入测试数据
insert into for_delete (name) values ('A'), ('B'), ('C');

-- 删除整表数据
delete from for_delete;

-- 再插入一条数据,自增 id 在原值上增长
insert into for_delete (name) values ('D');

注意 :删除整表操作要慎用!DELETE 删除整表后,自增 id 会在原值上继续增长。

6.3 截断表(truncate)

语法:

sql 复制代码
truncate [table] table_name

注意:这个操作慎用!

  1. 只能对整表操作,不能像 delete 一样针对部分数据操作
  2. 实际上 mysql 不对数据操作,所以比 delete 更快,但是 truncate 在删除数据的时候,并不经过真正的事务,所以无法回滚
  3. 会重置 auto_increment 项
sql 复制代码
-- 准备测试表
create table for_truncate (
    id int primary key auto_increment,
    name varchar(20)
);

-- 插入测试数据
insert into for_truncate (name) values ('A'), ('B'), ('C');

-- 截断整表数据,注意影响行数是 0,所以实际上没有对数据真正操作
truncate for_truncate;

-- 再插入一条数据,自增 id 重新增长
insert into for_truncate (name) values ('D');

7. 插入查询结果

语法:

sql 复制代码
insert into table_name [(column [, column ...])] select ...

案例:删除表中的重复记录,重复的数据只能有一份:

sql 复制代码
-- 创建原数据表
create table duplicate_table (id int, name varchar(20));

-- 插入测试数据
insert into duplicate_table values
    (100, 'aaa'),
    (100, 'aaa'),
    (200, 'bbb'),
    (200, 'bbb'),
    (300, 'ccc');

-- 创建一张空表 no_duplicate_table,结构和 duplicate_table 一样
create table no_duplicate_table like duplicate_table;

-- 将 duplicate_table 的去重数据插入到 no_duplicate_table
insert into no_duplicate_table select distinct * from duplicate_table;

-- 通过重命名表,实现原子的去重操作
rename table duplicate_table to old_duplicate_table,
    no_duplicate_table to duplicate_table;

8. 聚合函数

函数 说明
count([distinct] expr) 返回查询到的数据的数量
sum([distinct] expr) 返回查询到的数据的总和,不是数字没有意义
avg([distinct] expr) 返回查询到的数据的平均值,不是数字没有意义
max([distinct] expr) 返回查询到的数据的最大值,不是数字没有意义
min([distinct] expr) 返回查询到的数据的最小值,不是数字没有意义

8.1 统计班级共有多少同学

sql 复制代码
-- 使用 * 做统计,不受 NULL 影响
select count(*) from students;

-- 使用表达式做统计
select count(1) from students;

8.2 统计班级收集的 qq 号有多少

sql 复制代码
-- null 不会计入结果
select count(qq) from students;

8.3 统计本次考试的数学成绩分数个数

sql 复制代码
-- count(math) 统计的是全部成绩
select count(math) from exam_result;

-- count(distinct math) 统计的是去重后的成绩个数
select count(distinct math) from exam_result;
相关推荐
dishugj2 小时前
HANA集群计划内切换与维护操作
java·linux·数据库
夏幻灵10 小时前
JavaScript this 面试:五种绑定规则、优先级与常见面试陷阱
开发语言·javascript·面试
IvorySQL11 小时前
PostgreSQL 日报|修复截断 zstd 备份检测(10 月 9 日)
数据库·postgresql
刘胡子大叔11 小时前
SQL 脚本的导入顺序
数据库·sql
代码什么用11 小时前
Spring对IoC的实现
数据库·spring
hz5678914 小时前
涉密视频会议设备配置指南:终端、音视频采集与配套设施选型
服务器·网络·数据库·安全·实时音视频·信息与通信·智能硬件
广州浮点FLOATLIC14 小时前
许可证服务器迁移后软件打不开:研发 IT 怎样定位连接问题
linux·服务器·数据库
程序员Sunday14 小时前
MySQL 为什么使用 B+ 树索引?把范围查询、回表和覆盖索引连起来
数据库·mysql
半杯咖啡半行码14 小时前
Qt开发实战:数据库、MV 模式、QProcess与串口通信全攻略
数据库·qt