MySQL CRUD | 增删改查知识点总结

表的增删改查(CRUD)

CRUD:Create(新增)、Retrieve(读取查询)、Update(更新)、Delete(删除)


1 Create 新增数据

1.1 语法

sql 复制代码
INSERT [INTO] table_name
[(column [, column ...])]
VALUES (value_list) [, (value_list)] ...

value_list:值列表,值的数量、顺序必须和前面列保持一致

1.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)
);

1.3 单行全列插入

省略列名,必须按照建表全部字段顺序写值;自增id可以直接写NULL,数据库自动自增赋值

sql 复制代码
INSERT INTO students VALUES (100, 10000, '唐三藏', NULL);
INSERT INTO students VALUES (101, 10001, '孙悟空', '11111');
-- 查询结果
SELECT * FROM students;

|-----|-------|------|-------|
| id | sn | name | qq |
| 100 | 10000 | 唐三藏 | NULL |
| 101 | 10001 | 孙悟空 | 11111 |

1.4 多行指定列插入

只写需要插入的字段,值顺序、数量严格对应指定列

sql 复制代码
INSERT INTO students (id, sn, name) VALUES
    (102, 20001, '曹孟德'),
    (103, 20002, '孙仲谋');
SELECT * FROM students;

|-----|-------|------|-------|
| id | sn | name | qq |
| 100 | 10000 | 唐三藏 | NULL |
| 101 | 10001 | 孙悟空 | 11111 |
| 102 | 20001 | 曹孟德 | NULL |
| 103 | 20002 | 孙仲谋 | NULL |

1.5 插入冲突(主键/唯一键重复)

主键重复报错

sql 复制代码
INSERT INTO students (id, sn, name) VALUES (100, 10010, '唐大师');
-- ERROR 1062 (23000): Duplicate entry '100' for key 'PRIMARY'

唯一键重复报错

sql 复制代码
INSERT INTO students (sn, name) VALUES (20001, '曹阿瞒');
-- ERROR 1062 (23000): Duplicate entry '20001' for key 'sn'

1.5.1 插入否则更新 ON DUPLICATE KEY UPDATE

主键或者唯一键冲突时,不去报错,直接更新指定字段

sql 复制代码
INSERT INTO students (id, sn, name) VALUES (100, 10010, '唐大师')
ON DUPLICATE KEY UPDATE sn = 10010, name = '唐大师';

0 row affected:存在冲突,更新前后值完全一样,无修改

1 row affected:原本无数据,直接插入成功

2 row affected:原有冲突数据,执行更新操作

获取受影响行数

sql 复制代码
SELECT ROW_COUNT();

1.6 REPLACE替换插入

主键/唯一键无冲突:直接插入;主键/唯一键冲突:先删除旧数据,再插入新数据

sql 复制代码
REPLACE INTO students (sn, name) VALUES (20001, '曹阿瞒');

1 row affected:无冲突,新增

2 row affected:有冲突,删除旧行,插入新行


2 Retrieve 查询数据 SELECT

2.1 查询完整语法

sql 复制代码
SELECT [DISTINCT] {* | [column [, column] ...]}
[FROM table_name]
[WHERE ...]
[ORDER BY column [ASC | DESC], ...]
[LIMIT ...]

2.2 准备成绩测试表

sql 复制代码
CREATE TABLE exam_result (
    id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '同学姓名',
    name VARCHAR(20) NOT NULL,
    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);

2.2.1 全列查询 *

业务开发 禁止直接SELECT * ,弊端:查询字段越多,传输数据量越大,性能差;无法使用索引优化

sql 复制代码
SELECT * FROM exam_result;

|----|------|---------|------|---------|
| id | name | chinese | math | english |
| 1 | 唐三藏 | 67 | 98 | 56 |
| 2 | 孙悟空 | 87 | 78 | 77 |
| 3 | 猪悟能 | 88 | 98 | 90 |
| 4 | 曹孟德 | 82 | 84 | 67 |
| 5 | 刘玄德 | 55 | 85 | 45 |
| 6 | 孙权 | 70 | 73 | 78 |
| 7 | 宋公明 | 75 | 65 | 30 |

2.2.2 指定列查询

列顺序可以和建表顺序不一致,自定义展示顺序

sql 复制代码
SELECT id, name, english FROM exam_result;

2.2.3 查询字段为表达式

  1. 常量表达式
sql 复制代码
SELECT id, name, 10 FROM exam_result;
  1. 单字段运算
sql 复制代码
SELECT id, name, english + 10 FROM exam_result;
  1. 多字段运算(三科总分)
sql 复制代码
SELECT id, name, chinese + math + english FROM exam_result;

2.2.4 查询结果设置别名 AS

AS关键字可以省略,给计算出来的新列起名字,仅用于展示,WHERE不能使用别名

sql 复制代码
SELECT id, name, chinese + math + english 总分 FROM exam_result;

2.2.5 DISTINCT 结果去重

去除查询结果里面重复行

sql 复制代码
-- 原始,存在重复98
SELECT math FROM exam_result;
-- 去重
SELECT DISTINCT math FROM exam_result;

2.3 WHERE条件筛选

根据条件过滤行,满足条件才保留,WHERE不能使用select里面定义的别名

2.3.1 运算符总表

|-------------------|------------------------------------|
| 运算符 | 说明 |
| > >= < <= | 大于、大于等于、小于、小于等于 |
| = | 等于,NULL不安全,NULL = NULL结果是NULL,不是真 |
| <=> | 等于,NULL安全,NULL <=> NULL返回1(true) |
| != , <> | 不等于 |
| BETWEEN a0 AND a1 | 闭区间 a0,a1,字段>=a0 并且 <=a1 |
| IN(值1,值2,值3) | 字段等于括号里面任意一个值 |
| IS NULL | 是空值 |
| IS NOT NULL | 不是空值 |
| LIKE | 模糊匹配;%任意多个字符(包含0个);_严格匹配1个任意字符 |

逻辑运算符

|-----|-------------------|
| 运算符 | 说明 |
| AND | 并且,两边条件全部为真,整体才为真 |
| OR | 或者,任意一个条件为真,整体为真 |
| NOT | 取反,真变假,假变真 |

2.3.2 案例练习

案例1:英语不及格(<60)

sql 复制代码
SELECT name, english FROM exam_result WHERE english < 60;

案例2:语文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;

案例3:数学是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);

案例4:姓孙(模糊查询LIKE)

sql 复制代码
--孙开头,后面任意字符
SELECT name FROM exam_result WHERE name LIKE '孙%';
--孙后面严格1个字
SELECT name FROM exam_result WHERE name LIKE '孙_';

案例5:语文成绩 > 英语成绩(字段和字段对比)

sql 复制代码
SELECT name,chinese,english FROM exam_result WHERE chinese > english;

案例6:总分小于200

⚠WHERE不能用别名,必须完整写表达式

sql 复制代码
SELECT name, chinese+math+english 总分 FROM exam_result
WHERE chinese + math + english < 200;

案例7:语文>80 并且名字不姓孙

sql 复制代码
SELECT name, chinese FROM exam_result
WHERE chinese>80 AND name NOT LIKE '孙%';

案例8:综合条件:名字姓孙 OR (总分>200 AND 语文<数学 AND 英语>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);

案例9:NULL查询

普通=无法匹配NULL,必须IS NULL / <=>

sql 复制代码
--查询qq不为null的学生
SELECT name,qq FROM students WHERE qq IS NOT NULL;

NULL对比坑点

sql 复制代码
--全部结果都是NULL,判断失效!
SELECT NULL = NULL, NULL = 1, NULL =0;
--NULL安全相等判断
SELECT NULL <=> NULL, NULL <=>1, NULL <=>0;

2.4 ORDER BY 结果排序

2.4.1语法说明

• ASC:升序(从小到大)默认,可以省略

• DESC:降序(从大到小)

重要:不带ORDER BY的查询,返回顺序无定义,业务绝对不能依赖默认顺序!

sql 复制代码
SELECT ... FROM table_name [WHERE ...]
ORDER BY 列名 [ASC|DESC] , [列名2 ASC|DESC]...;

多字段排序优先级:写在前面优先排序,第一列值相同,才会按照第二列排序

ORDER BY可以使用select别名!

案例1:数学成绩升序

sql 复制代码
SELECT name,math FROM exam_result ORDER BY math;

案例2:qq升序排序

MySQL中NULL视为比任何数值都小,升序NULL出现在最上方;降序NULL出现在最底部

sql 复制代码
SELECT name,qq FROM students ORDER BY qq;
SELECT name,qq FROM students ORDER BY qq DESC;

案例3:多字段排序:数学降序,英语升序,语文升序

sql 复制代码
SELECT name,math,english,chinese FROM exam_result
ORDER BY math DESC, english, chinese;

案例4:按总分降序(别名排序)

sql 复制代码
SELECT name, chinese+math+english 总分 FROM exam_result
ORDER BY 总分 DESC;

案例5:条件筛选后排序

WHERE写在ORDER BY前面

sql 复制代码
SELECT name,math FROM exam_result
WHERE name LIKE '孙%' OR name LIKE '曹%'
ORDER BY math DESC;

2.5 LIMIT 分页筛选结果

下标从0开始!

语法3种写法

sql 复制代码
--写法1:从0开始,取n条
SELECT ... FROM table LIMIT n;
--写法2:从s下标开始,取n条
SELECT ... FROM table LIMIT s, n;
--写法3(推荐,可读性强)LIMIT n OFFSET s
SELECT ... FROM table LIMIT n OFFSET s;

开发规范:不确定表多大,查询全表必须加 LIMIT 1,防止数据量巨大卡死数据库

案例:每页3条,分页展示

sql 复制代码
--第1页 offset=0
SELECT id,name,math,english,chinese FROM exam_result
ORDER BY id LIMIT 3 OFFSET 0;
--第2页 offset=3
SELECT id,name,math,english,chinese FROM exam_result
ORDER BY id LIMIT 3 OFFSET 3;
--第3页 offset=6,不足3条,查到多少返回多少
SELECT id,name,math,english,chinese FROM exam_result
ORDER BY id LIMIT 3 OFFSET 6;

3 Update 更新数据

3.1语法

sql 复制代码
UPDATE table_name SET column=expr [,column2=expr2...]
[WHERE ...] [ORDER BY ...] [LIMIT ...]

⚠超级大坑:不加WHERE条件,会更新整张表全部数据!!严禁裸写UPDATE

案例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='孙悟空';

案例2:一次性更新多列,曹孟德数学60,语文70

sql 复制代码
UPDATE exam_result SET math=60,chinese=70 WHERE name='曹孟德';

案例3:基于原值更新,数学+30

sql 复制代码
UPDATE exam_result SET math = math + 30 WHERE name='宋公明';

案例4:不带WHERE,全表语文*2(危险操作)

sql 复制代码
UPDATE exam_result SET chinese = chinese *2;

案例5:排序+limit限制更新行数

sql 复制代码
UPDATE exam_result SET math = math+30
ORDER BY chinese+math+english LIMIT 3;

4 Delete 删除数据

4.1 Delete语法

sql 复制代码
DELETE FROM table_name [WHERE ...] [ORDER BY...] [LIMIT...]

⚠不加WHERE,删除整张表全部数据!自增id不会重置,再次插入id接着之前数字继续增加

案例1:删除孙悟空这条成绩

sql 复制代码
DELETE FROM exam_result WHERE name='孙悟空';

案例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=4,自增计数器没有清零!
INSERT INTO for_delete(name) VALUES ('D');

4.2 TRUNCATE 截断清空表

sql 复制代码
TRUNCATE [TABLE] table_name;

4.2.1 TRUNCATE 和 DELETE清空全表区别

  1. TRUNCATE只能清空整张表,不能加WHERE删部分行

  2. TRUNCATE底层不走事务,无法回滚;DELETE可以事务回滚恢复

  3. TRUNCATE执行速度远快于DELETE

  4. TRUNCATE重置AUTO_INCREMENT自增计数器,新插入id重新从1开始

sql 复制代码
CREATE TABLE for_truncate (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(20)
);
INSERT INTO for_truncate(name) VALUES ('A'),('B'),('C');
TRUNCATE for_truncate;
--再次插入id=1,计数器清零
INSERT INTO for_truncate(name) VALUES ('D');

5 插入查询结果(复制去重案例)

把一条SELECT查询出来的结果,直接插入另一张表

语法

sql 复制代码
INSERT INTO table_name [(列...)] SELECT ...;

案例:去除一张表里面完全重复的数据

sql 复制代码
--原始重复表
CREATE TABLE duplicate_table(id int,name varchar(20));
INSERT INTO duplicate_table VALUES
(100,'aaa'),
(100,'aaa'),
(200,'bbb'),
(200,'bbb'),
(200,'bbb'),
(300,'ccc');
--创建空表,结构完全一样
CREATE TABLE no_duplicate_table LIKE 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;

6 聚合函数(统计函数)

对多行数据做统计运算,NULL不会参与计算

|--------------------------|-----------------------------------------|
| 函数 | 说明 |
| COUNT(DISTINCT expr) | 统计行数,COUNT(*)统计所有行,COUNT(列)统计该列非NULL行数 |
| SUM(DISTINCT expr) | 求和,只对数字有效,自动忽略NULL |
| AVG(DISTINCT expr) | 求平均值,只对数字有效,自动忽略NULL |
| MAX(DISTINCT expr) | 求最大值,忽略NULL |
| MIN(DISTINCT expr) | 求最小值,忽略NULL |

案例1:统计学生总人数

sql 复制代码
SELECT COUNT(*) FROM students;
SELECT COUNT(1) FROM students;

案例2:统计qq有效填写人数(NULL不计入)

sql 复制代码
SELECT COUNT(qq) FROM students;

案例3:数学成绩去重之后有多少种分数

sql 复制代码
SELECT COUNT(DISTINCT math) FROM exam_result;

案例4:数学总分

sql 复制代码
SELECT SUM(math) FROM exam_result;
--条件求和:数学小于60总分,无数据返回NULL
SELECT SUM(math) FROM exam_result WHERE math <60;

案例5:三科平均分

sql 复制代码
SELECT AVG(chinese+math+english) 平均总分 FROM exam_result;

案例6:英语最高分

sql 复制代码
SELECT MAX(english) FROM exam_result;

案例7:大于70分数学最低分

sql 复制代码
SELECT MIN(math) FROM exam_result WHERE math>70;

7 GROUP BY 分组查询

按照指定列,把相同值的行分到同一组,配合聚合函数做分组统计

7.1语法

sql 复制代码
SELECT 列1,聚合函数(列2) FROM 表名
GROUP BY 列1;

规则:select后面非聚合字段,必须写在group by里面

案例:经典emp员工表练习

  1. 查询每个部门平均工资、最高工资
sql 复制代码
SELECT deptno,AVG(sal),MAX(sal) FROM EMP GROUP BY deptno;
  1. 查询每个部门每个岗位平均工资,最低工资(多字段分组)
sql 复制代码
SELECT deptno,job,AVG(sal),MIN(sal) FROM EMP GROUP BY deptno,job;

7.2 HAVING分组之后过滤

WHERE:分组之前筛选原始行,不能使用聚合函数

HAVING:分组统计结束之后,对分组结果过滤,可以使用聚合函数

案例:筛选平均工资小于2000的部门

sql 复制代码
SELECT deptno,AVG(sal) myavg FROM EMP
GROUP BY deptno
HAVING myavg <2000;

8 SQL关键字执行顺序

执行先后顺序(不是书写顺序!!)

FROM → ON → JOIN → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT

  1. from:确定查询哪张表

  2. where:筛选原始数据行

  3. group by:分组

  4. 分组内聚合计算

  5. having:过滤分组之后结果

  6. select:计算别名,展示列

  7. distinct:去重

  8. order by:排序

  9. limit:分页截取


9 高频易错坑点总结

  1. WHERE条件不能使用select别名;ORDER BY可以使用别名

  2. NULL不能用=匹配,只能IS NULL / <=>

  3. UPDATE、DELETE不加WHERE会修改/删除全表!!

  4. TRUNCATE无法回滚,重置自增id;DELETE不清零自增id

  5. count(列名)不会统计NULL;count(*)统计全部行数,包含NULL

  6. group by select非聚合列必须出现在group by字段中

  7. having过滤分组结果,可以写聚合函数;where不能写聚合函数

  8. 排序必须手动写ORDER BY,绝对不要依赖数据库默认顺序

  9. 模糊匹配:%匹配任意长度;_严格匹配单个字符

相关推荐
竹枝溪2 小时前
MySQL进阶:约束、多表设计、多表查询与事务
java·数据库·mysql·事务·子查询·acid·多表查询
技术长镜头2 小时前
别再只会“加索引”:从磁盘页到 B+Tree,彻底理解 MySQL 索引的设计与运行
后端·mysql
weixin_431600442 小时前
NestJS 入门(9):连上数据库,SQL 写在哪?
数据库·后端·sql·学习·nest.js
math_hongfan2 小时前
一对多的数据库姻缘:ArkTS 为鸿蒙订单设计外键与明细表
数据库·华为·harmonyos
城管不管3 小时前
MySQL 慢查询完整排查
java·服务器·jvm·数据库·mysql·spring·面试
XLYcmy3 小时前
PDF论文处理器 - 功能总结
数据库·python·pdf·csv·pymupdf·dify·文本分割
树码小子3 小时前
MySQL 的事务隔离级别(重点面试题)
数据库·mysql
01_ice3 小时前
MySQL表的约束
数据库·sql·mysql
北漂燕郊杨哥3 小时前
Win11 环境下 phpStudy 安装 Redis 最新版,并为 PHP 8.5.9(NTS)配置 redis 扩展
数据库·redis·php
AlfredZhao3 小时前
SQL JOIN 写法:把多表关联条件写清楚
sql