您的位置:首页 > 科技 > 能源 > 柳州网站建设_python基础教程电子书下载_个人网页怎么做_世界疫情最新数据

柳州网站建设_python基础教程电子书下载_个人网页怎么做_世界疫情最新数据

2025/1/18 20:04:55 来源:https://blog.csdn.net/lirendada/article/details/144880799  浏览:    关键词:柳州网站建设_python基础教程电子书下载_个人网页怎么做_世界疫情最新数据
柳州网站建设_python基础教程电子书下载_个人网页怎么做_世界疫情最新数据

文章目录

  • 前言
  • Ⅰ. 创建新数据
    • 1、`insert`语句
    • 2、插入否则更新 -- 替换
    • 3、替换 -- `replace`
  • Ⅱ. 检索数据
    • 1、`select`语句
      • ① 全列查询
      • ② 指定列查询
      • ③ 查询字段为表达式
      • ④ 为查询结果指定别名 `as`
      • ⑤ 结果去重 `distinct`
    • 2、`where` 条件
      • 🎏 `where` 条件在 `sql` 语句中的执行顺序
      • 比较运算符
      • 逻辑运算符
      • 使用案例
        • ① 英语不及格的同学及英语成绩,即小于60分
        • ② 语文成绩在 [80, 90] 分的同学及语文成绩
        • ③ 数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩
        • ④ 姓孙的同学及孙某同学
        • ⑤ 语文成绩好于英语成绩的同学
        • ⑥ 总分在 200 分以上的同学
        • ⑦ 语文成绩 > 80 并且不姓孙的同学
        • ⑧ 猪某同学,否则要求总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80
        • ⑨ NULL 的查询
    • 3、`order by` 结果排序
      • 🎏`order by`子句在 `sql` 语句中的执行顺序
      • 使用案例
        • ① 同学及数学成绩,按数学成绩升序显示
        • ② 同学及 qq 号,按 qq 号排序显示
        • ③ 查询同学各门成绩,依次按 数学降序,英语升序,语文升序的方式显示
        • ④ 查询同学及总分,由高到低
        • ⑤ 查询姓孙的同学或者姓曹的同学数学成绩,结果按数学成绩由高到低显示
    • 4、`limit` 筛选分页结果
      • 🎏 `limit` 子句在 `sql` 语句中的执行顺序
  • Ⅲ. 更新数据
    • 1、`update`语句
    • 2、使用案例
      • ① 将孙悟空同学的数学成绩变更为 80 分
      • ② 将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分
      • ③ 将总成绩倒数前三的 3 位同学的数学成绩加上 30 分
      • ④ 将所有同学的语文成绩更新为原来的 2 倍
  • Ⅳ. 删除数据
    • 1、`delete`删除数据
      • ① 删除孙悟空同学的考试成绩
      • ② 删除整张表数据
    • 2、`truncate`截断表
      • ① 删除整张表数据
    • 3、两者的区别
  • Ⅴ. 插入查询结果
    • 1、语法
    • 2、案例
  • Ⅵ. 聚合函数
    • 1、常见聚合函数
    • 2、案例
      • ① 统计班级共有多少同学
      • ② 统计班级收集的数学成绩有多少
      • ③ 统计本次考试的数学成绩分数去重后的个数
      • ④ 统计数学成绩总分
      • ⑤ 统计平均总分
      • ⑥ 返回英语最高分
      • ⑦ 返回 > 70 分以上的数学最低分
  • Ⅶ. `group by`分组查询 && `having` 结果过滤
    • 1、`group by`语法
    • 案例准备工作
    • 2、`having`语法
    • 3、案例
      • ① 显示每个部门的每种岗位的平均工资和最低工资
      • ② 显示平均工资低于2000的部门和它的平均工资
  • 实战OJ题

前言

​ 一般来说,数据库的基本操作叫做 CRUD,是一种常见的编程术语,它代表了四个基本的数据库操作:创建(Create)、读取(Read)、更新(Update)和删除(Delete)。这些操作用于对数据库中的数据进行管理。

​ 上面说的四种基本操作,是对四种操作的总览,具体使用的语句细分下去是有差别的,下面我们分别来学习它们!

SQL查询中各个关键字的执行先后顺序: from > on> join > where > group by > with > having > select> distinct > order by > limit

Ⅰ. 创建新数据

1、insert语句

insert [into] table_name
[(列名, 列名, ...)]
values (value_list) [, (value_list), ...] 其中:value_list: value, [, value, ...] 
  • 选项说明:
    • 其中方括号表示可选项
    • column 表示列字段
    • value 表示对应各自 column 要填入的值
    • 插入新数据的时候,columnvalue 一定要一一对应

​ 根据 columnvalue_list 的个数不同,可以划分为下面的情况:
在这里插入图片描述

2、插入否则更新 – 替换

​ 由于 主键 或者 唯一键 对应的值已经存在而导致插入失败:

-- 主键冲突
insert into students (id, sn, name) values (1, 10010, 'lirendada');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'-- 唯一键冲突
insert into students (sn, name) values (102, 'james');
ERROR 1062 (23000): Duplicate entry '20001' for key 'sn'

​ 我们可以选择性的进行同步更新操作语法:

insert ... on DUPLICATE key update column = value [, column = value, ...] 

​ 其中省略号代表的是 insert 语句的语法,当插入冲突的时候才会触发后面的这些语法!

在这里插入图片描述

其中在我们插入数据之后经常会有下面三个情况:

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

3、替换 – replace

​ 其实这和上面的操作是一样的,只不过有了 replace 这个语句专门来解决这种下面的情况:

  • 主键 或者 唯一键 没有冲突,则直接插入
  • 主键 或者 唯一键 如果冲突,则删除后再插入

​ 其语法如下所示:

replace into 表名 (要插入的列字段) values (列字段对应的值);

​ 举个例子:

在这里插入图片描述

Ⅱ. 检索数据

1、select语句

select 语句是一种用于从数据库中检索数据的 SQL 语句。它允许我们 指定要检索的列和表,并可以使用条件来过滤结果

select[distinct] 								# 去重{* 或者 {列名 [, 列名] ...}       [from] 表名							  # 要检索的表名[where ...]								# 用于指定条件来过滤结果[order by column [asc | desc], ...]		# 排序[limit ...]								# 限定筛选条数
  • 参数说明:
    • 其中 方括号的内容代表可以省略
    • select 语句的选项不止有上面这些,后面会慢慢介绍到其它的!

​ 下面我们创建的表结构这里直接给出来,因为不是这里的重点:

-- 创建表结构
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);

① 全列查询

通常情况下 不建议使用 * 进行全列查询,原因如下所示:

  1. 查询的列越多,意味着需要传输的数据量越大。

  2. 可能会影响到索引的使用。(索引待后面讲解)

mysql> 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 |
+----+-----------+---------+------+---------+
7 rows in set (0.00 sec)

② 指定列查询

指定列的顺序不需要按定义表的顺序来,可以按照查询的顺序来显示。记得 指定列中间用逗号分隔开

mysql> select id,chinese,name,math from exam_result;
+----+---------+-----------+------+
| id | chinese | name      | math |
+----+---------+-----------+------+
|  1 |      67 | 唐三藏    |   98 |
|  2 |      87 | 孙悟空    |   78 |
|  3 |      88 | 猪悟能    |   98 |
|  4 |      82 | 曹孟德    |   84 |
|  5 |      55 | 刘玄德    |   85 |
|  6 |      70 | 孙权      |   73 |
|  7 |      75 | 宋公明    |   65 |
+----+---------+-----------+------+
7 rows in set (0.00 sec)

③ 查询字段为表达式

-- 表达式不包含字段
mysql> select id,name,10 from exam_result;
+----+-----------+----+
| id | name      | 10 |
+----+-----------+----+
|  1 | 唐三藏    | 10 |
|  2 | 孙悟空    | 10 |
|  3 | 猪悟能    | 10 |
|  4 | 曹孟德    | 10 |
|  5 | 刘玄德    | 10 |
|  6 | 孙权      | 10 |
|  7 | 宋公明    | 10 |
+----+-----------+----+
7 rows in set (0.00 sec)-- 表达式包含一个字段
mysql> select id,name,10+math from exam_result;
+----+-----------+---------+
| id | name      | 10+math |
+----+-----------+---------+
|  1 | 唐三藏    |     108 |
|  2 | 孙悟空    |      88 |
|  3 | 猪悟能    |     108 |
|  4 | 曹孟德    |      94 |
|  5 | 刘玄德    |      95 |
|  6 | 孙权      |      83 |
|  7 | 宋公明    |      75 |
+----+-----------+---------+
7 rows in set (0.00 sec)-- 表达式包含多个字段
mysql> select id,name,10+math+chinese+english from exam_result;
+----+-----------+-------------------------+
| id | name      | 10+math+chinese+english |
+----+-----------+-------------------------+
|  1 | 唐三藏    |                     231 |
|  2 | 孙悟空    |                     252 |
|  3 | 猪悟能    |                     286 |
|  4 | 曹孟德    |                     243 |
|  5 | 刘玄德    |                     195 |
|  6 | 孙权      |                     231 |
|  7 | 宋公明    |                     180 |
+----+-----------+-------------------------+
7 rows in set (0.00 sec)

④ 为查询结果指定别名 as

​ 语法如下所示:

select 列字段 [as] alias_name [...] from 表名;

​ 举个例子就懂了:

mysql> select id,name,math+chinese+english as 总分 from exam_result;
+----+-----------+--------+
| id | name      | 总分   |
+----+-----------+--------+
|  1 | 唐三藏    |    221 |
|  2 | 孙悟空    |    242 |
|  3 | 猪悟能    |    276 |
|  4 | 曹孟德    |    233 |
|  5 | 刘玄德    |    185 |
|  6 | 孙权      |    221 |
|  7 | 宋公明    |    170 |
+----+-----------+--------+
7 rows in set (0.00 sec)

⑤ 结果去重 distinct

-- 去重前
mysql> select math+chinese+english as 总分 from exam_result;
+--------+
| 总分   |
+--------+
|    221 |
|    242 |
|    276 |
|    233 |
|    185 |
|    221 |
|    170 |
+--------+
7 rows in set (0.00 sec)-- 去重后
mysql> select distinct math+chinese+english as 总分 from exam_result;
+--------+
| 总分   |
+--------+
|    221 |
|    242 |
|    276 |
|    233 |
|    185 |
|    170 |
+--------+
6 rows in set (0.00 sec)

2、where 条件

​ 这里的 where 条件其实就是对我们已经选择的列字段,进行某种条件筛选的策略!其实就相当于我们以前在学 c/c++ 的时候所学的 if 语句,所以肯定也有对应的比较、逻辑运算符供我们使用!

​ 要注意的是,别名不能用在 where 条件中

🎏 where 条件在 sql 语句中的执行顺序

在这里插入图片描述

​ 为什么强调这个执行顺序呢❓❓❓

​ 这是因为只有当我们理解了执行顺序之后,才会理解一些 mysql 的错误语句到底错在哪,或者是要做什么工作!

​ 比如为什么 不能在 where 语句中使用别名,这是因为别名是在 select 部分使用的,是为了最后呈现出来表字段的别名。如果在 where 语句使用了 select 语句部分的别名,那么因为执行顺序问题,where 语句在 select 语句之前就执行了,肯定就找不到该别名去执行,就报错了!

比较运算符

运算符说明
><大于,大于等于,小于,小于等于
=等于,对于 NULL 不安全,例如 NULL = NULL 的结果是 NULL
<=>等于,对于 NULL 安全,例如 NULL <=> NULL 的结果是 TRUE/1
!=<>不等于
between a and b范围匹配为 [a, b],如果 a ≤ value ≤ b,返回 TRUE/1
in (option, ...)如果是 option 中的任意一个,返回 TRUE/1
is null判断是否为 null
is not null判断是否不为 null
like模糊匹配,% 表示任意多个(包括 0 个)任意字,_ 表示任意一个字符

逻辑运算符

运算符说明
and多个条件必须都为 TRUE/1,结果才是 TRUE/1
or任意一个条件为 TRUE/1,结果为 TRUE/1
not条件为 TRUE/1,结果为 FALSE/0

使用案例

① 英语不及格的同学及英语成绩,即小于60分
-- 筛选前
mysql> select name,english as '英语' from exam_result;
+-----------+--------+
| name      | 英语   |
+-----------+--------+
| 唐三藏    |     56 |
| 孙悟空    |     77 |
| 猪悟能    |     90 |
| 曹孟德    |     67 |
| 刘玄德    |     45 |
| 孙权      |     78 |
| 宋公明    |     30 |
+-----------+--------+
7 rows in set (0.00 sec)-- 筛选后
mysql> select name,english as '英语' from exam_result where english < 60;
+-----------+--------+
| name      | 英语   |
+-----------+--------+
| 唐三藏    |     56 |
| 刘玄德    |     45 |
| 宋公明    |     30 |
+-----------+--------+
3 rows in set (0.00 sec)
② 语文成绩在 [80, 90] 分的同学及语文成绩

​ 除了下面的 between and 之外,还可以使用 and,但是太麻烦了,这里就不演示了!

-- 筛选前
mysql> select name,chinese as '语文' from exam_result;
+-----------+--------+
| name      | 语文   |
+-----------+--------+
| 唐三藏    |     67 |
| 孙悟空    |     87 |
| 猪悟能    |     88 |
| 曹孟德    |     82 |
| 刘玄德    |     55 |
| 孙权      |     70 |
| 宋公明    |     75 |
+-----------+--------+
7 rows in set (0.00 sec)-- 使用between and筛选
mysql> select name,chinese as '语文' from exam_result where chinese between 80 and 90;
+-----------+--------+
| name      | 语文   |
+-----------+--------+
| 孙悟空    |     87 |
| 猪悟能    |     88 |
| 曹孟德    |     82 |
+-----------+--------+
3 rows in set (0.00 sec)
③ 数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩
-- 筛选前
mysql> select name,math as '数学' from exam_result;
+-----------+--------+
| name      | 数学   |
+-----------+--------+
| 唐三藏    |     98 |
| 孙悟空    |     78 |
| 猪悟能    |     98 |
| 曹孟德    |     84 |
| 刘玄德    |     85 |
| 孙权      |     73 |
| 宋公明    |     65 |
+-----------+--------+
7 rows in set (0.00 sec)-- 使用or筛选
mysql> select name,math as '数学' from exam_result where math=58 or math=59 or math=98 or math=99;
+-----------+--------+
| name      | 数学   |
+-----------+--------+
| 唐三藏    |     98 |
| 猪悟能    |     98 |
+-----------+--------+
2 rows in set (0.00 sec)

​ 还可用 in 进行筛选,更加的优雅:

-- 使用in筛选,更加的优雅!
mysql> select name,math as '数学' from exam_result where math in(58, 59, 98, 99);
+-----------+--------+
| name      | 数学   |
+-----------+--------+
| 唐三藏    |     98 |
| 猪悟能    |     98 |
+-----------+--------+
2 rows in set (0.00 sec)
④ 姓孙的同学及孙某同学

​ 解释一下这个要求,姓孙的同学他们的名字是可以不定长的,但是孙某同学,就是固定名长就是一个,是这个意思!

​ 像这种模糊的需求,我们就可以用模糊匹配 like 来解决!

-- 筛选前
mysql> select name from exam_result;
+-----------+
| name      |
+-----------+
| 唐三藏    |
| 孙悟空    |
| 猪悟能    |
| 曹孟德    |
| 刘玄德    |
| 孙权      |
| 宋公明    |
+-----------+
7 rows in set (0.00 sec)-- 通过like以及两个通配符来筛选,两者用or连接
-- % 表示匹配任意多个(包括0个)任意字符
-- _ 表示匹配严格的一个任意字符
mysql> select name from exam_result where name like '孙%' or name like '孙_';
+-----------+
| name      |
+-----------+
| 孙悟空    |
| 孙权      |
+-----------+
2 rows in set (0.00 sec)
⑤ 语文成绩好于英语成绩的同学
-- 筛选前
mysql> select name,chinese as '语文',math as '数学' from exam_result;
+-----------+--------+--------+
| name      | 语文   | 数学   |
+-----------+--------+--------+
| 唐三藏    |     67 |     98 |
| 孙悟空    |     87 |     78 |
| 猪悟能    |     88 |     98 |
| 曹孟德    |     82 |     84 |
| 刘玄德    |     55 |     85 |
| 孙权      |     70 |     73 |
| 宋公明    |     75 |     65 |
+-----------+--------+--------+
7 rows in set (0.00 sec)-- 筛选后
mysql> select name,chinese as '语文',math as '数学' from exam_result where chinese > math;
+-----------+--------+--------+
| name      | 语文   | 数学   |
+-----------+--------+--------+
| 孙悟空    |     87 |     78 |
| 宋公明    |     75 |     65 |
+-----------+--------+--------+
2 rows in set (0.00 sec)
⑥ 总分在 200 分以上的同学

​ 这里需要注意的是,别名不能用在 where 条件中!具体原因是和语句的执行有关,上面讲过!

-- 筛选前
mysql> select name, chinese+math+english '总分' from exam_result;
+-----------+--------+
| name      | 总分   |
+-----------+--------+
| 唐三藏    |    221 |
| 孙悟空    |    242 |
| 猪悟能    |    276 |
| 曹孟德    |    233 |
| 刘玄德    |    185 |
| 孙权      |    221 |
| 宋公明    |    170 |
+-----------+--------+
7 rows in set (0.00 sec)-- 筛选后
mysql> select name, chinese+math+english '总分' from exam_result where chinese+math+english > 200;
+-----------+--------+
| name      | 总分   |
+-----------+--------+
| 唐三藏    |    221 |
| 孙悟空    |    242 |
| 猪悟能    |    276 |
| 曹孟德    |    233 |
| 孙权      |    221 |
+-----------+--------+
5 rows in set (0.00 sec)
⑦ 语文成绩 > 80 并且不姓孙的同学
-- 筛选前
mysql> select name, chinese from exam_result where chinese>80;
+-----------+---------+
| name      | chinese |
+-----------+---------+
| 孙悟空    |      87 |
| 猪悟能    |      88 |
| 曹孟德    |      82 |
+-----------+---------+
3 rows in set (0.00 sec)-- 通过and和not配合达到筛选目的
mysql> select name, chinese from exam_result where chinese>80 and name not like '孙%';
+-----------+---------+
| name      | chinese |
+-----------+---------+
| 猪悟能    |      88 |
| 曹孟德    |      82 |
+-----------+---------+
2 rows in set (0.00 sec)
⑧ 猪某同学,否则要求总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80
mysql> select name,chinese,math,english,chinese+math+english '总分' from exam_result where name like '猪%' and 				chinese+math+english>200 and chineese<math and english>80;
+-----------+---------+------+---------+--------+
| name      | chinese | math | english | 总分   |
+-----------+---------+------+---------+--------+
| 猪悟能    |      88 |   98 |      90 |    276 |
+-----------+---------+------+---------+--------+
1 row in set (0.00 sec)
⑨ NULL 的查询
-- 查询 students 表
+-----+-------+-----------+-------+
| id  | sn    | name      | qq    |
+-----+-------+-----------+-------+
| 100 | 10010 | 唐大师    | NULL   |
| 101 | 10001 | 孙悟空    | 11111  |
| 103 | 20002 | 孙仲谋    | NULL   |
| 104 | 20001 | 曹阿瞒    | NULL   |
+-----+-------+-----------+-------+
4 rows in set (0.00 sec)-- 查询 qq 号已知的同学姓名
select name, qq from students where qq is not NULL;
+-----------+-------+
| name      | qq 	|
+-----------+-------+
| 孙悟空 	  | 11111 |
+-----------+-------+
1 row in set (0.00 sec)

​ 下面再列举一下 NULLNULL 的比较,=<=> 的区别:

select NULL = NULL, NULL = 1, NULL = 0;
+-------------+----------+----------+
| NULL = NULL | NULL = 1 | NULL = 0 |
+-------------+----------+----------+
| NULL 		  | NULL 	 | NULL 	|
+-------------+----------+----------+
1 row in set (0.00 sec)select NULL <=> NULL, NULL <=> 1, NULL <=> 0;
+---------------+------------+------------+
| NULL <=> NULL | NULL <=> 1 | NULL <=> 0 |
+---------------+------------+------------+
| 1 			| 0 		 | 0 		  |
+---------------+------------+------------+
1 row in set (0.00 sec)

3、order by 结果排序

​ 在 mysql 中,order by 子句用于 对查询结果进行排序。它可以按照一个或多个列的值进行升序或降序排序。

​ 以下是 order by 子句的基本语法:

select 列名 from 表名 order by 列名 [asc|desc];

​ 其中,列名是要排序的列的名称,表名是要查询的表的名称。ASC(ascending) 表示按升序排序(默认),DESC(descending) 表示按降序排序。

​ 如果要按多个列进行排序,可以在 order by 子句中指定多个列名,并用逗号分隔它们。查询结果将首先按第一个列进行排序,然后按第二个列进行排序,以此类推。

​ 注意事项:

  • 没有 order by 子句的查询,返回的顺序是未定义的,永远不要依赖原来的插入表的这个顺序!
  • 多字段排序,排序优先级随书写顺序!(可以结合下面的案例③)
  • order by 子句中是 可以使用列别名 的!(这个和子句的执行顺序有关系!)
  • order by 子句必须放在 where 条件后面使用!

🎏order by子句在 sql 语句中的执行顺序

在这里插入图片描述

​ 从上图可以清晰看到执行的顺序,最重要的是第三步也就是 select 子句,它虽然是进行筛选和显示的执行,但是其实它这两个步骤是分开的,当加入了 order by 子句之后,select 子句会先进行筛选,目的是筛选出符合条件的数据集,然后 再交给第四步也就是 order by 子句进行排序,最后再回到 select 子句中进行最后的显示!

​ 这也是为什么 order by 子句可以使用 select 子句中的别名的原因!

使用案例

① 同学及数学成绩,按数学成绩升序显示
mysql> select name,math from exam_result order by math asc;		#升序
+-----------+------+
| name      | math |
+-----------+------+
| 宋公明    |   65 |
| 孙权      |   73 |
| 孙悟空    |   78 |
| 曹孟德    |   84 |
| 刘玄德    |   85 |
| 唐三藏    |   98 |
| 猪悟能    |   98 |
+-----------+------+
7 rows in set (0.00 sec)mysql> select name,math from exam_result order by math desc;	#降序
+-----------+------+
| name      | math |
+-----------+------+
| 唐三藏    |   98 |
| 猪悟能    |   98 |
| 刘玄德    |   85 |
| 曹孟德    |   84 |
| 孙悟空    |   78 |
| 孙权      |   73 |
| 宋公明    |   65 |
+-----------+------+
7 rows in set (0.00 sec)
② 同学及 qq 号,按 qq 号排序显示
-- NULL 视为比任何值都小,升序出现在最上面
select name, qq from students order by qq;
+-----------+-------+
| name 		| qq 	|
+-----------+-------+
| 唐大师 	  | NULL |
| 孙仲谋 	  | NULL |
| 曹阿瞒 	  | NULL |
| 孙悟空 	  | 11111|
+-----------+-------+
4 rows in set (0.00 sec)-- NULL 视为比任何值都小,降序出现在最下面
select name, qq from students order by qq desc;
+-----------+-------+
| name 		| qq 	|
+-----------+-------+
| 孙悟空 	  | 11111 |
| 唐大师 	  | NULL |
| 孙仲谋 	  | NULL |
| 曹阿瞒 	  | NULL |
+-----------+-------+
4 rows in set (0.00 sec)
③ 查询同学各门成绩,依次按 数学降序,英语升序,语文升序的方式显示

​ 注意,多字段排序,排序优先级随书写顺序!所以如果 math 高的话,就算 english 低了也会排在前面!

mysql> select name,math,english,chinese from exam_result order by math desc,english asc,chinese asc;
+-----------+------+---------+---------+
| name      | math | english | chinese |
+-----------+------+---------+---------+
| 唐三藏    |   98 |      56 |      67 |
| 猪悟能    |   98 |      90 |      88 |
| 刘玄德    |   85 |      45 |      55 |
| 曹孟德    |   84 |      67 |      82 |
| 孙悟空    |   78 |      77 |      87 |
| 孙权      |   73 |      78 |      70 |
| 宋公明    |   65 |      30 |      75 |
+-----------+------+---------+---------+
7 rows in set (0.00 sec)
④ 查询同学及总分,由高到低

说明 order by 中也可以使用表达式

mysql> select name,chinese+math+english as '总分' from exam_result order by chinese+math+english desc;
+-----------+--------+
| name      | 总分   |
+-----------+--------+
| 猪悟能    |    276 |
| 孙悟空    |    242 |
| 曹孟德    |    233 |
| 唐三藏    |    221 |
| 孙权      |    221 |
| 刘玄德    |    185 |
| 宋公明    |    170 |
+-----------+--------+
7 rows in set (0.00 sec)

​ 除此之外,order by 子句中是可以使用列别名的

mysql> select name,chinese+math+english as '总分' from exam_result order by '总分' desc;
+-----------+--------+
| name      | 总分   |
+-----------+--------+
| 唐三藏    |    221 |
| 孙悟空    |    242 |
| 猪悟能    |    276 |
| 曹孟德    |    233 |
| 刘玄德    |    185 |
| 孙权      |    221 |
| 宋公明    |    170 |
+-----------+--------+
7 rows in set (0.00 sec)
⑤ 查询姓孙的同学或者姓曹的同学数学成绩,结果按数学成绩由高到低显示

​ 从下面的操作可以看出 order by 子句要放在 where 条件的后面

mysql> select name,math from exam_result where name like '孙%' or name like '曹%' order by math desc;
+-----------+------+
| name      | math |
+-----------+------+
| 曹孟德    |   84 |
| 孙悟空    |   78 |
| 孙权      |   73 |
+-----------+------+
3 rows in set (0.00 sec)-- order by子句要放在where条件的后面!
mysql> select name,math from exam_result order by math desc where name like '孙%' or name like '曹%';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where name like '%' or name like '%'' at line 1

4、limit 筛选分页结果

limit 是一个用于限制查询结果返回的子句。它可以用于 指定从查询结果中返回的行数,也可以用于指定返回结果的偏移量

​ 一般语法如下:

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

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

​ 举个例子,按 idname 进行分页,每页 3 条记录,分别显示 第 123 页(这里使用上述的第三种方式):

mysql> select id,name from exam_result limit 3 offset 0;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | 唐三藏    |
|  2 | 孙悟空    |
|  3 | 猪悟能    |
+----+-----------+
3 rows in set (0.00 sec)mysql> select id,name from exam_result limit 3 offset 3;
+----+-----------+
| id | name      |
+----+-----------+
|  4 | 曹孟德    |
|  5 | 刘玄德    |
|  6 | 孙权      |
+----+-----------+
3 rows in set (0.00 sec)mysql> select id,name from exam_result limit 3 offset 6;
+----+-----------+
| id | name      |
+----+-----------+
|  7 | 宋公明    |
+----+-----------+
1 row in set (0.00 sec)

🎏 limit 子句在 sql 语句中的执行顺序

​ 很明显,因为 limit 子句是用来限制 ”显示“ 结果的,那么就是在比较靠后的步骤中才执行的!

在这里插入图片描述

Ⅲ. 更新数据

1、update语句

​ 在 mysql 中,update 语句用于更新表中的数据。它的基本语法如下:

update 表名 set column1=value1 [, column2=value2, ...] [where 条件] [order by ...] [limit ...];

​ 注意,如果没有指定 where 子句,update 语句将会更新表中的所有行。因此,在使用 update 语句时,请确保提供正确的条件,以避免意外更新整个表的数据。

2、使用案例

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

-- 查看原数据
mysql> select name,math from exam_result where name='孙悟空';
+-----------+------+
| name      | math |
+-----------+------+
| 孙悟空    |   78 |
+-----------+------+
1 row in set (0.00 sec)-- 数据更新
mysql> update exam_result set math=80 where name='孙悟空';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0-- 查看更新后数据
mysql> select name,math from exam_result where name='孙悟空';
+-----------+------+
| name      | math |
+-----------+------+
| 孙悟空    |   80 |
+-----------+------+
1 row in set (0.00 sec)

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

-- 一次更新多个列-- 查看原数据
mysql> select name,math,chinese from exam_result where name='曹孟德';
+-----------+------+---------+
| name      | math | chinese |
+-----------+------+---------+
| 曹孟德    |   84 |      82 |
+-----------+------+---------+
1 row in set (0.00 sec)-- 数据更新
mysql> update exam_result set math=60,chinese=70 where name='曹孟德';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0-- 查看更新后数据
mysql> select name,math,chinese from exam_result where name='曹孟德';
+-----------+------+---------+
| name      | math | chinese |
+-----------+------+---------+
| 曹孟德    |   60 |      70 |
+-----------+------+---------+
1 row in set (0.00 sec)

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

-- 更新值为原值基础上变更-- 查看原数据
mysql> select name,math+chinese+english total from exam_result order by total asc limit 3;
+-----------+-------+
| name      | total |
+-----------+-------+
| 宋公明    |   170 |
| 刘玄德    |   185 |
| 曹孟德    |   197 |
+-----------+-------+
3 rows in set (0.00 sec)-- 数据更新,注意mysql不支持math += 30这种语法
mysql> update exam_result set math=math+30 order by math+chinese+english limit 3;
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3  Changed: 3  Warnings: 0-- 按总成绩排序后查询结果
mysql> select name,math+chinese+english total from exam_result order by total asc limit 3;
+-----------+-------+
| name      | total |
+-----------+-------+
| 宋公明    |   200 |
| 刘玄德    |   215 |
| 唐三藏    |   221 |
+-----------+-------+
3 rows in set (0.00 sec)

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

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

-- 没有 WHERE 子句,则更新全表-- 查看原数据
mysql> select name,chinese from exam_result;
+-----------+---------+
| name      | chinese |
+-----------+---------+
| 唐三藏    |      67 |
| 孙悟空    |      87 |
| 猪悟能    |      88 |
| 曹孟德    |      70 |
| 刘玄德    |      55 |
| 孙权      |      70 |
| 宋公明    |      75 |
+-----------+---------+
7 rows in set (0.00 sec)-- 数据更新
mysql> update exam_result set chinese=chinese*2;
Query OK, 7 rows affected (0.00 sec)
Rows matched: 7  Changed: 7  Warnings: 0-- 查看更新后数据
mysql> select name,chinese from exam_result;
+-----------+---------+
| name      | chinese |
+-----------+---------+
| 唐三藏    |     134 |
| 孙悟空    |     174 |
| 猪悟能    |     176 |
| 曹孟德    |     140 |
| 刘玄德    |     110 |
| 孙权      |     140 |
| 宋公明    |     150 |
+-----------+---------+
7 rows in set (0.00 sec)

Ⅳ. 删除数据

1、delete删除数据

delete 语句用于从表中删除满足指定条件的行,可以根据需要删除部分或全部数据。delete 语句是一种 DML(数据操作语言)操作,它 会生成事务日志,并且可以回滚

delete 语句的语法如下:

delete from 表名 [where 条件] [order by ...] [limit ...];

​ 另外注意的是,这里说的删除操作,都是针对表中的数据,而不是删除表的操作的

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

-- 查看原数据
mysql> select * from exam_result where name='孙悟空';
+----+-----------+---------+------+---------+
| id | name      | chinese | math | english |
+----+-----------+---------+------+---------+
|  2 | 孙悟空    |     174 |   80 |      77 |
+----+-----------+---------+------+---------+
1 row in set (0.00 sec)-- 删除数据
mysql> delete from exam_result where name='孙悟空';
Query OK, 1 row affected (0.00 sec)-- 查看删除结果
mysql> select * from exam_result where name='孙悟空';
Empty set (0.00 sec)

② 删除整张表数据

​ 注意,删除整表操作要慎用

-- 准备测试表
create table for_delete (id int primary key auto_increment,name varchar(20));-- 插入测试数据
insert into for_delete (name) values ('A'), ('B'), ('C');-- 查看测试数据
mysql> select * from for_delete;
+----+------+
| id | name |
+----+------+
|  1 | A    |
|  2 | B    |
|  3 | C    |
+----+------+
3 rows in set (0.00 sec)
-- 删除整表数据
mysql> delete from for_delete;
Query OK, 3 rows affected (0.00 sec)-- 查看删除结果
mysql> select * from for_delete;
Empty set (0.00 sec)
-- 再插入一条数据,自增 id 在原值上增长
mysql> insert into for_delete (name) values('liren');
Query OK, 1 row affected (0.01 sec)-- 查看数据
mysql> select * from for_delete;
+----+-------+
| id | name  |
+----+-------+
|  4 | liren |
+----+-------+
1 row in set (0.00 sec)-- 查看表结构,会有 AUTO_INCREMENT=n 项,依然是不变的!这和下面的截断表不太一样!
mysql> show create table for_delete\G;
*************************** 1. row ***************************Table: for_delete
Create Table: CREATE TABLE `for_delete` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(20) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

2、truncate截断表

truncate 语句用于 删除表中的所有数据,它会将表重置为空表,但保留表的结构truncate 语句是一种 DDL(数据定义语言)操作,它 不会生成事务日志,并且不能回滚

truncate 语句的语法如下:

truncate table 表名;

​ 使用说明:

  1. 只能对整表操作,不能像 delete 一样针对部分数据操作;
  2. 实际上 truncate 不对数据操作,所以比 delete 更快,但是 truncate 在删除数据的时候,并不经过真正的事务,所以无法回滚!
  3. 会重置 auto_increment
  4. 这个语句慎用

​ 操作和 delete 基本是一样的,只不过没有 where 等子句罢了,只能对整个表进行操作!

​ 下面我们同样做个例子,看看它们的区别:

① 删除整张表数据

-- 准备测试表
create table for_truncate (id int primary key auto_increment,name varchar(20));
Query OK, 0 rows affected (0.02 sec)-- 插入测试数据
insert into for_delete (name) values ('A'), ('B'), ('C');-- 查看测试数据
mysql> select * from for_truncate;
+----+------+
| id | name |
+----+------+
|  1 | A    |
|  2 | B    |
|  3 | C    |
+----+------+
3 rows in set (0.00 sec)
-- 截断整表数据,注意影响行数是 0,所以实际上没有对数据真正操作
mysql> truncate table for_truncate;
Query OK, 0 rows affected (0.01 sec)-- 查看删除结果
mysql> select * from for_truncate;
Empty set (0.00 sec)
-- 再插入一条数据,自增 id 在重新增长
mysql> insert into for_truncate (name) values('liren');
Query OK, 1 row affected (0.01 sec)-- 查看数据
mysql> select * from for_truncate;
+----+-------+
| id | name  |
+----+-------+
|  1 | liren |
+----+-------+
1 row in set (0.00 sec)-- 查看表结构,会有 AUTO_INCREMENT=2 项,这是因为我们重新插入了一条数据后的,说明auto_increment被重新设置了
mysql> 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.01 sec)

3、两者的区别

下面是 deletetruncate 之间的一些主要区别:

  • delete 语句是逐行删除数据,而 truncate 语句是一次性删除表中所有数据。
  • delete 语句可以使用 where 子句来指定删除的条件,而 truncate 语句不支持 where 子句。
  • delete 语句会 生成事务日志,并且可以回滚,而 truncate 语句 不会生成事务日志,并且不能回滚
  • delete 语句在删除每一行时都会触发相应的触发器(如果有定义的话),而 truncate 语句不会触发触发器。
  • delete 语句的 执行速度相对较慢,特别是在删除大量数据时,而 truncate 语句的 执行速度相对较快,因为它是一次性删除所有数据。

根据具体的需求和场景,选择使用 delete 还是 truncate 取决于你想要删除的数据量、是否需要回滚以及是否需要触发触发器等因素。

Ⅴ. 插入查询结果

1、语法

​ 其实我们可以通过 insert 子句和 select 子句的配合,达到插入一些需要的查询结果的目的!

​ 其语法如下所示:

insert into 表名 [(列名 [, 列名 ...])] select ...

​ 这语法无非就是将 insert 子句后面 values() 部分替换成 select 子句罢了!

2、案例

​ 下面给出一个案例:要求删除表中的重复记录,让重复的数据只能有一份。

​ 这里的思路是这样子的:一般我们很少直接对原表中的数据进行操作,而是先创建一个新表,其表结构和原表的结构是一模一样的。然后通过 insert+select 语句将去重的结果进行插入到新表,最后将原表使用 rename table 语句重命名为旧表当作备份,而新表重命名为原表使用!

可能有人会问,为什么最后是通过 rename table 语句重命名的方式来操作❓❓❓

rename table 命令在 mysql 中是一个 原子操作,它会自动处理表的元数据和相关的索引、触发器等信息,它还会确保在重命名过程中不会丢失任何数据。

​ 举个例子,假设我们今天在 linux 中要上传一个文件到指定目录中,并且要求是原子操作,而因为这个文件的大小很大,所以上传速度很慢,此时其它在该目录下的业务也就自然被阻塞了。

​ 为了解决这个问题,我们可以先将这个文件,上传到一个临时目录中,然后等上传结束之后,通过 mv 指令直接更改目录名为指定的目录名,这个操作也是原子操作,符合要求,并且一步到位,不会干扰到其它业务的处理!

​ 所以使用重命名的方式,其实就是 单纯地想等一切当作都就绪,然后再统一放入、更新、生效等!这对于 rename table 来说也是如此!

​ 预处理:

-- 创建原数据表
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 一样
mysql> create table no_duplicate_table like duplicate_table;
Query OK, 0 rows affected (0.00 sec)-- 将 duplicate_table 的去重数据插入到 no_duplicate_table
mysql> insert into no_duplicate_table select distinct * from duplicate_table;
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0-- 通过重命名表,实现原子的去重操作
mysql> rename table duplicate_table to old_duplicate_table, no_duplicate_table to duplicate_table;
Query OK, 0 rows affected (0.02 sec)-- 查看最终结果
mysql> select * from duplicate_table;
+------+------+
| id   | name |
+------+------+
|  100 | aaa  |
|  200 | bbb  |
|  300 | ccc  |
+------+------+
3 rows in set (0.00 sec)mysql> select * from old_duplicate_table;
+------+------+
| id   | name |
+------+------+
|  100 | aaa  |
|  100 | aaa  |
|  200 | bbb  |
|  200 | bbb  |
|  200 | bbb  |
|  300 | ccc  |
+------+------+
6 rows in set (0.00 sec)

Ⅵ. 聚合函数

1、常见聚合函数

​ 这些常见的聚合函数可以与 select 语句一起使用,用于对数据进行汇总和统计操作:

函数声明
count( [distinct] 列名 )用于计算指定列或表中的行数
sum( [distinct] 列名 )用于计算指定列或表中数值列的总和(不是数字没有意义)
avg( [distinct] 列名 )用于计算指定列或表中数值列的平均值(不是数字没有意义)
max( [distinct] 列名 )用于找出指定列或表中数值列的最大值(不是数字没有意义)
min( [distinct] 列名 )用于找出指定列或表中数值列的最小值(不是数字没有意义)
group_concat( 列名 分隔符 )用于将指定列的值连接成一个字符串,并用指定的分隔符分隔

​ 注意,在使用聚合函数的时候,如果后面没有跟着 group by 指定的列字段的话,那么 select 语句是除了聚会函数以外,不能列举其它无关的列字段

2、案例

① 统计班级共有多少同学

-- 最好使用 * 做统计,不受 NULL 影响mysql> select count(*) from exam_result;
+----------+
| count(*) |
+----------+
|        7 |
+----------+
1 row in set (0.00 sec)

② 统计班级收集的数学成绩有多少

-- NULL 不会计入结果mysql> select count(math) from exam_result;
+-------------+
| count(math) |
+-------------+
|           7 |
+-------------+
1 row in set (0.00 sec)

③ 统计本次考试的数学成绩分数去重后的个数

-- COUNT(DISTINCT math) 统计的是去重成绩数量
mysql> select count(distinct math) from exam_result;
+----------------------+
| count(distinct math) |
+----------------------+
|                    6 |
+----------------------+
1 row in set (0.01 sec)-- 可以使用别名
mysql> select count(distinct math) 数学 from exam_result;
+--------+
| 数学   |
+--------+
|      6 |
+--------+
1 row in set (0.00 sec)

④ 统计数学成绩总分

mysql> select sum(math) 数学总分 from exam_result;
+--------------+
| 数学总分     |
+--------------+
|          581 |
+--------------+
1 row in set (0.00 sec)

⑤ 统计平均总分

mysql> select avg(chinese+math+english) 平均总分 from exam_result;
+--------------------+
| 平均总分           |
+--------------------+
| 221.14285714285714 |
+--------------------+
1 row in set (0.00 sec)

⑥ 返回英语最高分

mysql> select max(english) 英语 from exam_result;
+--------+
| 英语   |
+--------+
|     90 |
+--------+
1 row in set (0.00 sec)-- 注意不能select无关的列字段
mysql> select name, max(english) 英语 from exam_result;
ERROR 1140 (42000): In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'testdb.exam_result.name'; this is incompatible with sql_mode=only_full_group_by

⑦ 返回 > 70 分以上的数学最低分

mysql> select min(math) 数学 from exam_result where math>70;
+--------+
| 数学   |
+--------+
|     73 |
+--------+
1 row in set (0.00 sec)

Ⅶ. group by分组查询 && having 结果过滤

1、group by语法

​ 在 mysql 中,group by 子句用于 将结果集按照指定列进行分组。它通常与聚合函数(如 SUMCOUNTAVG 等)一起使用,以便对每个组应用聚合函数并返回结果。

​ 其语法如下:

select 列名1, 列名2, ... 列名n from 表名 [where 条件] group by 列名1, 列名2, ... 列名n;

​ 在这个语法中,列名1,列名2,… 列名n 是想要按照其进行分组的列。我们可以指定一个或多个列作为分组依据,而 where 子句用于筛选出符合条件的行。

​ 注意事项:

  • group by 子句的 执行顺序是在 where 子句之后,在 select 子句之前的
  • 只要使用了 group by 子句,那么除了在 group by 中指定的列字段,以及聚合函数之外,其它列字段一般不能出现在 select 子句中

案例准备工作

  • 准备工作,创建一个雇员信息表(来自oracle 9i的经典测试表)
    • EMP员工表
    • DEPT部门表
    • SALGRADE工资等级表

​ 这里提前准备好了一个 sql 文件 scott_data.sql,它已经为我们做好了数据库的创建、表的创建和一些数据的插入:

在这里插入图片描述

​ 我们首先要理解一个点,就是 group by 子句是在聚合函数也就是 select 子句之前执行的,为什么呢❓❓❓

​ 一般来说,我们使用 group by 子句的就是为了将同一个列字段,再进行细分来进行分组统计。也就是说 分组的目的就是为了分组之后,更方便进行聚合统计

​ 下面我们举个例子,显示每个部门的平均工资和最高工资。

​ 我们先简单的打印出所有部门的平均工资和最高工资:

mysql> select avg(sal) 平均工资, max(sal) 最高工资 from emp;
+--------------+--------------+
| 平均工资     | 最高工资     |
+--------------+--------------+
|  2073.214286 |      5000.00 |
+--------------+--------------+
1 row in set (0.00 sec)

​ 我们再试试看打印出分组后的部门情况:

-- 分组前
mysql> select deptno 部门 from emp;
+--------+
| 部门   |
+--------+
|     20 |
|     30 |
|     30 |
|     20 |
|     30 |
|     30 |
|     10 |
|     20 |
|     10 |
|     30 |
|     20 |
|     30 |
|     20 |
|     10 |
+--------+
14 rows in set (0.00 sec)-- 分组后
mysql> select deptno 部门 from emp group by deptno;
+--------+
| 部门   |
+--------+
|     10 |
|     20 |
|     30 |
+--------+
3 rows in set (0.00 sec)

​ 此时我们再将两者结合:

mysql> select deptno 部门,avg(sal) 平均工资,max(sal) 最高工资 from emp group by deptno;
+--------+--------------+--------------+
| 部门   | 平均工资     | 最高工资     |
+--------+--------------+--------------+
|     10 |  2916.666667 |      5000.00 |
|     20 |  2175.000000 |      3000.00 |
|     30 |  1566.666667 |      2850.00 |
+--------+--------------+--------------+
3 rows in set (0.00 sec)

​ 它就将每个部门的平均工资和最高工资查询出来了!

​ 对于上述的操作,其实含义就是先将部门的列字段进行分组,分成不同的部门,即 group by deptno;此时只有当我们将这个分组好的几个部门交给 select 子句中的聚合函数去统计,其统计出来的才是各个部门的数据!

​ 其实可以想象 在逻辑上,分组操作其实就是将一张表,拆成了多张子表,然后再分别对各自的子表进行聚合统计

在这里插入图片描述

​ 反过来,如果说我们先将所有员工的平均工资都求出来,再进行分组,此时平均工资不就又乱套了,就得重新再求一遍分组中的平均工资等数据了,对不对,所以 mysql 没有这么笨,直接 group by 子句在 select 子句聚合统计前执行即可避免这个情况

2、having语法

​ 在 mysql 中,having 子句 用于在 group by 子句之后对结果进行过滤。它允许使用聚合函数对分组后的数据进行条件过滤。

​ 其语法如下:

select 列名 from 表名 [where 条件] group by 列名 having 条件

🎏注意事项:

  • having 子句中 可以使用 select 子句中的别名
  • having 子句中的条件 可以使用聚合函数(如SUMCOUNTAVG等)对分组后的数据进行过滤,只有满足 having 条件的分组才会被包含在结果中。
  • having 子句 只能在 group by 子句之后使用,并且用于过滤分组后的结果。如果 只需要对具体的任意列进行过滤,而不是对分组后的结果进行过滤,应该使用 where 子句。

​ 以下是一个示例,假设我们有一个名为 orders 的表,其中包含订单信息,包括订单号、客户ID和订单总金额。我们想要找到订单总金额大于 1000 的客户ID

select customer_id sum(order_count) total from orders group by customer_id having total>1000;

3、案例

① 显示每个部门的每种岗位的平均工资和最低工资

​ 其实相当于在上面的案例中,将部门分为不同的小组之后,将这些小组再次细分为不同的工作:

mysql> select deptno 部门,job 岗位,avg(sal) 平均工资,max(sal) 最高工资 from emp group by deptno,job;
+--------+-----------+--------------+--------------+
| 部门   | 岗位      | 平均工资     | 最高工资     |
+--------+-----------+--------------+--------------+
|     10 | CLERK     |  1300.000000 |      1300.00 |
|     10 | MANAGER   |  2450.000000 |      2450.00 |
|     10 | PRESIDENT |  5000.000000 |      5000.00 |
|     20 | ANALYST   |  3000.000000 |      3000.00 |
|     20 | CLERK     |   950.000000 |      1100.00 |
|     20 | MANAGER   |  2975.000000 |      2975.00 |
|     30 | CLERK     |   950.000000 |       950.00 |
|     30 | MANAGER   |  2850.000000 |      2850.00 |
|     30 | SALESMAN  |  1400.000000 |      1600.00 |
+--------+-----------+--------------+--------------+
9 rows in set (0.01 sec)

② 显示平均工资低于2000的部门和它的平均工资

having 经常和 group by 搭配使用,作用是对分组进行筛选,作用有些像 where,但是原理和 where 其实是不一样的!

mysql> select deptno 部门,avg(sal) 平均工资 from emp group by deptno having 平均工资<2000;
+--------+--------------+
| 部门   | 平均工资     |
+--------+--------------+
|     30 |  1566.666667 |
+--------+--------------+
1 row in set (0.00 sec)

​ 下面顺便来看一下它和 where 子句的区别:

mysql> select deptno 部门,avg(sal) 平均工资 from emp where sal<2000 group by deptno;
+--------+--------------+
| 部门   | 平均工资     |
+--------+--------------+
|     10 |  1300.000000 |
|     20 |   950.000000 |
|     30 |  1310.000000 |
+--------+--------------+
3 rows in set (0.00 sec)

​ 这是什么情况,为什么用 where 子句出来的有三个结果,而且其中部门一样的平均工资也不同呀❓❓

​ 还记得我们上面注意事项中提到的 having 子句和 where 子句它们的执行顺序是不同的吗,where 语句是在 from 之后也就是选表之后执行的筛选,此时筛选出来的是整个 sal 字段中少于 2000 的那些工资,最后再拿这些少于 2000 的去分组聚合统计,最后得到该结果。

​ 而 having 则是在分组聚合之后才拿到的数据,也就是之前整个 sal 字段的工资根据分组后聚合统计后,得到的结果,然后根据该结果再去筛选出来的最终结果,这无疑是不一样的操作,导致了不一样的结果,要区分开!

在这里插入图片描述

实战OJ题

  • 批量插入数据
  • 找出所有员工当前薪水salary情况
  • 查找最晚入职员工的所有信息
  • 查找入职员工时间排名倒数第三的员工所有信息
  • 查找薪水记录超过15条的员工号emp_no以及其对应的记录次数t
  • 查找重复的电子邮箱
  • Nth Highest Salary

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com