文章目录
- 📝Update
- 🌉 将孙悟空同学的数学成绩变更为 80 分
- 🌉 将曹孟德同学的数学成绩变更为60分,语文成绩变更为70分
- 🌉 将总成绩倒数前三的3位同学的数学成绩加上30分
- 🌉将所有同学的语文成绩更新为原来的2倍
- 🌠 Delete
- 🌉 删除数据
- 🌉 删除孙悟空同学的考试成绩
- 🌉 删除整张表数据
- 🌉 截断表
- 🌠 插入查询结果
- 🌠聚合函数
- 🌉统计班级共有多少同学
- 🌉统计班级收集的 qq 号有多少
- 🌉统计本次考试的数学成绩分数个数
- 🌉 统计数学成绩总分
- 🌉统计平均总分
- 🌉返回英语最高分
- 🌉返回 > 70 分以上的数学最低分
- 🌠group by子句的使用
- 🚩总结
📝Update
【MySQL 数据库】MySQL基本查询(第一节)
语法:
UPDATE table_name SET column = expr [, column = expr ...]
[WHERE ...] [ORDER BY ...] [LIMIT ...]
对查询到的结果进行列值更新
案例:
🌉 将孙悟空同学的数学成绩变更为 80 分
- 更新值为具体值
- 查看原数据
SELECT name, math FROM exam_result WHERE name = '孙悟空';| name | math |
| 孙悟空 | 78|
1 row in set (0.00 sec)
- 数据更新
UPDATE exam_result SET math = 80 WHERE name = '孙悟空'; Query OK, 1 row affected (0.04 sec)
Rows matched:1 Changed:1 warnings:0
- 查看更新后数据
SELECT name,math FROM exam_result WHERE name="孙悟空';| name | math |
|孙悟空 | 80|
1 row in set(0.00 sec)
🌉 将曹孟德同学的数学成绩变更为60分,语文成绩变更为70分
- 一次更新多个列
- 查看原数据
SELECT name,math,chinese FROM exam_result WHERE name="曹孟德';
| name | math | chinese|
| 曹孟德 | 84| 82|
1 row in set (0.00 sec)
- 数据更新
UPDATE exam_result SET math =60,chinese=70 WHERE name='曹孟德';
Query ok,1 row affected (0.14 sec) Rows matched:1 Changed:1 warnings:0
- 查看更新后数据
SELECT name,math,chinese FROM exam_result WHERE name="曹孟德';
| name | math | chinese|
| 曹孟德 | 60| 70|
1 row in set (0.00 sec)
🌉 将总成绩倒数前三的3位同学的数学成绩加上30分
- 更新值为原值基础上变更
- 别名可以在ORDER BY中使用
- 查看原数据
SELECT name, math,chinese+math+english总分FROM exam_result
ORDER BY总分LIMIT3;
| name | math| 总分 |
| 宋公明 | 65 | 170 |
| 刘玄德 | 85 | 185 |
| 曹孟德 | 60| 197 |
3 rows in set (0.00sec)
- 数据更新,不支持
math+=30
这种语法
UPDATE exam_result SET math = math+30
ORDER BY chinese + math+english LIMIT 3;
- 查看更新后数据
- 思考:这里还可以按总分升序排序取前3个么?
SELECT name,math,chinese +math+english总分FROM exam_result WHERE name IN('宋公明','刘玄德','曹孟德');
| name | math| 总分 |
| 曹孟德 | 90 | 227 |
| 刘玄德 | 115 | 215 |
| 宋公明 | 95 | 200 |
3 rows in set (0.00 sec)
- 按总成绩排序后查询结果
SELECT name,math,chinese+math+english总分FROM exam_result
ORDER BY总分LIMIT3;
| name | math| 总分 |
| 宋公明 | 95 | 200 |
| 刘玄德 | 115 | 215 |
| 唐三藏 | 98 | 221 |
3 rows in set (0.00 sec)
🌉将所有同学的语文成绩更新为原来的2倍
- 注意:更新全表的语句慎用!
- 没有WHERE子句,则更新全表
- 查看原数据
SELECT* FROM exam_result;
| id | name | chinese| math | english |
| 1 | 唐三藏 | 67 | 98 | 56 |
| 2 | 孙悟空 | 87 | 80 | 77 |
| 3 | 猪悟能 | 88 | 98 | 90 |
| 4 | 曹孟德 | 70 | 90 | 67 |
| 5 | 刘玄德 | 55 | 115 | 45 |
| 6 | 孙权 | 70| 73 | 78 |
| 7 | 宋公明 | 75| 95| 30 |
7 rows in set(0.00 sec)
- 数据更新
UPDATE exam_result SET chinese = chinese*2;
Query OK,7rows affected (0.00 sec)
Rows matched:7 changed:7 warnings:0
- 查看更新后数据
SELECT* FROM exam_result;
| id | name | chinese | math | english |
| 1 | 唐三藏 | 134 | 98 | 56 |
| 2 | 孙悟空 | 174 | 80 | 77 |
| 3 | 猪悟能 | 176 | 98 | 90 |
| 4 | 曹孟德 | 140 | 90 | 67 |
| 5 | 刘玄德 | 110 | 115 | 45 |
| 6 | 孙权 | 140 | 73 | 78 |
| 7 | 宋公明 | 150 | 95| 30 |
7 rows in set (0.00 sec)
🌠 Delete
🌉 删除数据
语法:
DELETE FROM table_name [WHERE...] [ORDER BY...] [LIMIT...]
案例:
🌉 删除孙悟空同学的考试成绩
- 查看原数据
SELECT*FROM exam_result WHERE name="孙悟空';
| id | name | chinese | math | english |
| 2 | 孙悟空 | 174 | 80 | 77 |
1 row in set(0.00 sec)
- 删除数据
DELETE FROM exam_result WHERE name='孙悟空';
Query OK,1 row affected (0.17sec)
- 查看删除结果
SELECT*FROM exam_result WHERE name="孙悟空';
Empty set (0.00 sec)
🌉 删除整张表数据
- 注意:删除整表操作要慎用!
- 准备测试表
CREATE TABLE for_delete ( id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (20);Query OK,0 rows affected (0.16 sec)
);
- 插入测试数据
INSERT INTO for_delete (name) VALUES ('A'),('B'),("c");Query OK,3 rows affected (1.05 sec) Records:3Duplicates:0 warnings:0
- 查看测试数据
SELECT* FROM for_delete;| id | name |
| 1 | A |
| 2 | B |
| 3 | C |
3 rows in set (0.00 sec)
- 删除整表数据
DELETE FROM for_delete;Query OK,3rows affected (0.00 sec)
- 查看删除结果
SELECT * FROM for_delete;Empty set (0.00 sec)
- 再插入一条数据,自增id在原值上增长
INSERT INTO for_delete (name) VALUES ("'D");
Query OK,1 row affected (0.00 sec)
- 查看数据
SELECT* FROM for_delete;| id | name |
| 4 | D |
1 row in set(0.00 sec)
- 查看表结构,会有AUTO_INCREMENT项
SHOW CREATE TABLE for_delete\G*************************** 1. row ***************************
Table: for_delete
create Table: CREATE TABLE for_delete'(
idint(11)NOT NULL AUTO_NCREMENT, "name' varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
🌉 截断表
语法:
TRUNCATE [TABLE] table_name
注意:
这个操作慎用
- 只能对整表操作,不能像 DELETE 一样针对部分数据操作;
- 实际上 MySQL 不对数据操作,所以比 DELETE 更快,但是TRUNCATE在删除数据的时候,并不经过真正的事物,所以无法回滚;
- 会重置 AUTO_INCREMENT 项
案例:
- 准备测试表
CREATE TABLE for_truncate (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20)
);
Query OK, 0 rows affected (0.16 sec)
- 插入测试数据
INSERT INTO for_truncate (name) VALUES ('A'), ('B'), ('C'); Query OK, 3 rows affected (1.05 sec)
Records: 3 Duplicates: 0 Warnings: 0
- 查看测试数据
SELECT * FROM for_truncate;
| id | name |
| 1 | A |
| 2 | B |
| 3 | C |
3 rows in set (0.00 sec)
- 截断整表数据,注意影响行数是 0,所以实际上没有对数据真正操作
TRUNCATE for_truncate;
Query OK, 0 rows affected (0.10 sec)
- 查看删除结果
SELECT * FROM for_truncate;
Empty set (0.00 sec)
- 再插入一条数据,自增 id 在重新增长
INSERT INTO for_truncate (name) VALUES ('D');
Query OK, 1 row affected (0.00 sec)
- 查看数据
SELECT * FROM for_truncate;
| id | name |
| 1 | D |
1 row in set (0.00 sec)
- 查看表结构,会有 AUTO_INCREMENT=2 项
SHOW CREATE TABLE for_truncate\G
*************************** 1. row ***************************
Table: for_truncate
Create Table: CREATE TABLE `for_truncate` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
🌠 插入查询结果
语法:
INSERT INTO table_name [(column [, column ...])] SELECT ...
案例:
删除表中的重复记录,重复的数据只能有一份
- 创建原数据表
CREATE TABLE duplicate_table (id int, name varchar(20));
Query OK, 0 rows affected (0.01 sec)
- 插入测试数据
INSERT INTO duplicate_table VALUES
(100, 'aaa'),
(100, 'aaa'),
(200, 'bbb'),
(200, 'bbb'),
(200, 'bbb'),
(300, 'ccc');
Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0
思路:
- 创建一张空表 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;Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
- 通过重命名表,实现原子的去重操作
RENAME TABLE duplicate_table TO old_duplicate_table,
no_duplicate_table TO duplicate_table;
Query OK, 0 rows affected (0.00 sec)
- 查看最终结果
SELECT * FROM duplicate_table; | id | name |
| 100 | aaa |
| 200 | bbb |
| 300 | ccc |
3 rows in set (0.00 sec)
🌠聚合函数
函数 | 说明 |
---|---|
COUNT([DISTINCT] expr) | 返回查询到的数据的 数量 |
SUM([DISTINCT] expr) | 返回查询到的数据的 总和,不是数字没有意义 |
AVG([DISTINCT] expr) | 返回查询到的数据的 平均值,不是数字没有意义 |
MAX([DISTINCT] expr) | 返回查询到的数据的 最大值,不是数字没有意义 |
MIN([DISTINCT] expr) | 返回查询到的数据的 最小值,不是数字没有意义 |
案例:
🌉统计班级共有多少同学
- 使用 * 做统计,不受 NULL 影响
SELECT COUNT(*) FROM students; | COUNT(*) |
| 4 |
1 row in set (0.00 sec)
- 使用表达式做统计
SELECT COUNT(1) FROM students;| COUNT(1) |
| 4 |
1 row in set (0.00 sec)
🌉统计班级收集的 qq 号有多少
- NULL 不会计入结果
SELECT COUNT(qq) FROM students; | COUNT(qq) |
| 1 |
1 row in set (0.00 sec)
🌉统计本次考试的数学成绩分数个数
- COUNT(math) 统计的是全部成绩
SELECT COUNT(math) FROM exam_result; | COUNT(math) |
| 6 |
1 row in set (0.00 sec)
- COUNT(DISTINCT math) 统计的是去重成绩数量
SELECT COUNT(DISTINCT math) FROM exam_result; | COUNT(math) |
| 6 |
1 row in set (0.00 sec)
🌉 统计数学成绩总分
SELECT SUM(math) FROM exam_result; | SUM(math) |
| 569 |
1 row in set (0.00 sec)
- 不及格 < 60 的总分,没有结果,返回 NULL
SELECT SUM(math) FROM exam_result WHERE math < 60;| SUM(math) |
| NULL |
1 row in set (0.00 sec)
🌉统计平均总分
SELECT AVG(chinese + math + english) 平均总分 FROM exam_result;
| 平均总分 |
| 297.5 |
🌉返回英语最高分
SELECT MAX(english) FROM exam_result; | MAX(english) |
| 90 |
1 row in set (0.00 sec)
🌉返回 > 70 分以上的数学最低分
SELECT MIN(math) FROM exam_result WHERE math > 70; | MIN(math) |
| 73 |
1 row in set (0.00 sec)
🌠group by子句的使用
- 语法结构:
SELECT 分组列1, 分组列2, 聚合函数(统计列) FROM 表名 [WHERE 筛选条件] -- 分组前筛选行 GROUP BY 分组列1, 分组列2 -- 按列分组(与SELECT中分组列顺序一致) [HAVING 分组筛选条件] -- 分组后筛选组 [ORDER BY 排序列]; -- 对分组结果排序
在select中使用group by 子句可以对指定列进行分组查询
select column1, column2, .. from table group by column;
- 核心规则:
SELECT
后出现的非聚合函数列,必须全部出现在GROUP BY
子句中(否则会报错,因为无法确定非分组列的取值)。GROUP BY
可以按多个列分组(先按第一列分组,同一组内再按第二列细分)。
2、经典案例解析(基于 EMP
员工表)
假设 EMP
表结构如下(简化版):
empno | ename | job | sal | deptno |
---|---|---|---|---|
1001 | 张三 | 经理 | 5000 | 10 |
1002 | 李四 | 职员 | 2000 | 10 |
1003 | 王五 | 职员 | 1800 | 10 |
1004 | 赵六 | 经理 | 4500 | 20 |
1005 | 钱七 | 职员 | 2200 | 20 |
案例 1:按单个列分组(部门)
需求:显示每个部门的平均工资、最高工资和员工人数。
SELECT deptno AS 部门编号,AVG(sal) AS 平均工资,MAX(sal) AS 最高工资,COUNT(*) AS 员工人数 -- 统计每个部门的人数
FROM EMP
GROUP BY deptno; -- 按部门编号分组
结果:
部门编号 | 平均工资 | 最高工资 | 员工人数 |
---|---|---|---|
10 | 2933.33 | 5000 | 3 |
20 | 3350.00 | 4500 | 2 |
案例 2:按多个列分组(部门+岗位)
需求:显示每个部门中,每种岗位的平均工资和最低工资。
SELECT deptno AS 部门编号,job AS 岗位,AVG(sal) AS 平均工资,MIN(sal) AS 最低工资
FROM EMP
GROUP BY deptno, job; -- 先按部门分组,同部门内再按岗位分组
结果:
部门编号 | 岗位 | 平均工资 | 最低工资 |
---|---|---|---|
10 | 经理 | 5000.00 | 5000 |
10 | 职员 | 1900.00 | 1800 |
20 | 经理 | 4500.00 | 4500 |
20 | 职员 | 2200.00 | 2200 |
案例 3:GROUP BY
+ HAVING
筛选分组结果
HAVING
用于对分组后的结果进行筛选(类似 WHERE
,但 WHERE
是分组前筛选行,HAVING
是分组后筛选组)。
需求:显示平均工资低于 3000 的部门及其平均工资。
SELECT deptno AS 部门编号,AVG(sal) AS 平均工资
FROM EMP
GROUP BY deptno
HAVING 平均工资 < 3000; -- 筛选分组后的平均工资
结果:
部门编号 | 平均工资 |
---|---|
10 | 2933.33 |
案例 4:GROUP BY
+ WHERE
+ HAVING
组合使用
需求:排除工资低于 1500 的员工后,统计每个部门的平均工资,且只显示平均工资高于 2500 的部门。
SELECT deptno AS 部门编号,AVG(sal) AS 平均工资
FROM EMP
WHERE sal >= 1500 -- 先排除工资<1500的员工(本案例中无此类员工,仅作示例)
GROUP BY deptno
HAVING 平均工资 > 2500; -- 再筛选平均工资>2500的部门
结果:
部门编号 | 平均工资 |
---|---|
10 | 2933.33 |
20 | 3350.00 |
三、常见错误与注意事项
-
SELECT
中的非聚合列必须在GROUP BY
中
错误示例:SELECT deptno, job, AVG(sal) FROM EMP GROUP BY deptno; -- 错误!job未在GROUP BY中
原因:分组后每个部门包含多个岗位,
job
列的值不唯一,无法确定显示哪一个。 -
HAVING
可以使用别名,WHERE
不能
正确:HAVING 平均工资 < 3000
(平均工资
是AVG(sal)
的别名)
错误:WHERE 平均工资 < 3000
(WHERE
不支持聚合函数别名) -
GROUP BY
的分组顺序不影响结果,但建议与SELECT
中分组列顺序一致
例如GROUP BY deptno, job
与GROUP BY job, deptno
分组逻辑不同,结果也不同。
🚩总结
点击刷题----->牛客刷题SQL篇
面试题:SQL查询中各个关键字的执行先后顺序 from > on> join > where > group by > with > having > select > distinct > order by > limit