数据库基础知识——聚合函数、分组查询

目录

一、聚合函数

[1.1 count](#1.1 count)

[1.1.1 统计整张表中所有记录的总条数](#1.1.1 统计整张表中所有记录的总条数)

[1.1.2 统计单列的数据](#1.1.2 统计单列的数据)

[1.1.3 统计单列记录+限制条件](#1.1.3 统计单列记录+限制条件)

[1.2 sum](#1.2 sum)

[1.3 avg](#1.3 avg)

[1.4 max, min](#1.4 max, min)

[二、group by 分组查询](#二、group by 分组查询)

[2.1 语法](#2.1 语法)

[2.2 示例](#2.2 示例)

[2.3 having](#2.3 having)


一、聚合函数

常用的聚合函数

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

1.1 count

sql 复制代码
mysql> select * from books;
+----+--------------------------+-----------+-------+-----------+---------------------+
| id | book_name                | author    | price | book_type | publish_date        |
+----+--------------------------+-----------+-------+-----------+---------------------+
| 29 | 阿波罗的秘密             | NULL      | 65.00 | NULL      | 2011-01-01 09:30:00 |
| 30 | 马达加斯加的企鹅         | 萨克斯    | 15.00 | NULL      | 2013-03-12 10:30:00 |
| 31 | 极简主义                 | NULL      | 32.00 | NULL      | 2019-04-28 00:50:00 |
| 32 | 另一种颜色               | NULL      | 32.50 | NULL      | 2019-10-01 07:10:00 |
| 33 | 夏日清泉                 | NULL      | 26.00 | NULL      | 2017-07-21 14:30:00 |
| 34 | NULL                     | NULL      | 34.00 | NULL      | 2014-06-01 11:11:00 |
| 35 | 冬日暖阳                 | 徐然      | 46.30 | NULL      | 2019-02-28 18:11:00 |
| 36 | 22岁                     | 桂芽紫    | 55.70 | NULL      | 2018-03-21 11:11:00 |
| 37 | 森林里有什么             | NULL      | 48.00 | NULL      | 2020-05-30 08:10:00 |
| 38 | 情书                     | NULL      |  NULL | NULL      | 2010-12-01 13:30:00 |
| 39 | 八音盒                   | switch    |  NULL | NULL      | 2021-06-15 15:20:00 |
| 40 | 灼烧的灵魂               | NULL      | 62.28 | NULL      | 2021-09-01 08:35:00 |
+----+--------------------------+-----------+-------+-----------+---------------------+
12 rows in set (0.01 sec)

1.1.1 统计整张表中所有记录的总条数

① 使用 * 做统计【推荐使用】

统计 books 表中有多少条记录:

sql 复制代码
mysql> select count(*) from books;
+----------+
| count(*) |
+----------+
|       12 |
+----------+
1 row in set (0.01 sec)

② 使用常量做统计

sql 复制代码
mysql> select count(1) from books;
+----------+
| count(1) |
+----------+
|       12 |
+----------+
1 row in set (0.00 sec)

mysql> select count(100) from books;  # 任意常数,无实际意义
+------------+
| count(100) |
+------------+
|         12 |
+------------+
1 row in set (0.00 sec)

1.1.2 统计单列的数据

统计有多少本书标识了作者姓名

指定列做统计,null 值不被计入结果集中

sql 复制代码
mysql> select count(author) from books;
+---------------+
| count(author) |
+---------------+
|             4 |
+---------------+
1 row in set (0.00 sec)

1.1.3 统计单列记录+限制条件

统计价格小于40的图书数量

sql 复制代码
mysql> select count(*) from books where price < 40;
+----------+
| count(*) |
+----------+
|        5 |
+----------+
1 row in set (0.00 sec)

mysql> select count(price) from books where price < 40;
+--------------+
| count(price) |
+--------------+
|            5 |
+--------------+
1 row in set (0.00 sec)

1.2 sum

只能统计单列数据类型为数值 的列,并且值为 null 的数据行不参与统计

sql 复制代码
mysql> select sum(price) from books;
+------------+
| sum(price) |
+------------+
|     416.78 |
+------------+
1 row in set (0.00 sec)


mysql> select sum(author) from books;
+-------------+
| sum(author) |
+-------------+
|           0 |
+-------------+
1 row in set, 4 warnings (0.00 sec)  # 统计非数值的列会发出警告信息

mysql> show warnings;
+---------+------+-----------------------------------------------+
| Level   | Code | Message                                       |
+---------+------+-----------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: '萨克斯'    |
| Warning | 1292 | Truncated incorrect DOUBLE value: '徐然'      |
| Warning | 1292 | Truncated incorrect DOUBLE value: '桂芽紫'    |
| Warning | 1292 | Truncated incorrect DOUBLE value: 'switch'    |
+---------+------+-----------------------------------------------+
4 rows in set (0.00 sec)

1.3 avg

括号里面可以是单列数据,也可以是多列数据

sql 复制代码
-- 单列统计平均值
mysql> select avg(price) from books;
+------------+
| avg(price) |
+------------+
|  41.678000 |
+------------+
1 row in set (0.00 sec)


-- 多列统计平均值
mysql> select * from game;
+------+-----------+---------+-------+--------------+--------------+
| id   | name      | lifebar | power | constitution | intelligence |
+------+-----------+---------+-------+--------------+--------------+
|    1 | 孙悟空    |     100 |   100 |          100 |           80 |
|    3 | 沙悟净    |     100 |    70 |           80 |           77 |
|    6 | 红孩儿    |     100 |    50 |          100 |           50 |
|    7 | 牛魔王    |     100 |    76 |           89 |           50 |
+------+-----------+---------+-------+--------------+--------------+
4 rows in set (0.00 sec)

mysql> select avg(power+constitution+intelligence) as 总属性值 from game;
+--------------+
| 总属性值     |
+--------------+
|     230.5000 |
+--------------+
1 row in set (0.00 sec)

1.4 max, min

找出 game 表中 power 最高值和 intelligence 最低值

多个聚合函数可以同时被使用

sql 复制代码
mysql> select max(power),min(intelligence) from game;
+------------+-------------------+
| max(power) | min(intelligence) |
+------------+-------------------+
|        100 |                50 |
+------------+-------------------+
1 row in set (0.00 sec)

使用别名

sql 复制代码
mysql> select max(power) 最高力量值,min(intelligence) '最低智力值' from game;
+-----------------+-----------------+
| 最高力量值      | 最低智力值      |
+-----------------+-----------------+
|             100 |              50 |
+-----------------+-----------------+
1 row in set (0.00 sec)

同一列可以使用不同聚合函数

sql 复制代码
mysql> select max(power) 最高力量值,min(power) 最低力量值 from game;
+-----------------+-----------------+
| 最高力量值      | 最低力量值      |
+-----------------+-----------------+
|             100 |              50 |
+-----------------+-----------------+
1 row in set (0.00 sec)

二、group by 分组查询

group by 子句的作用是通过⼀定的规则将⼀个数据集划分成若干个小的分组,然后针对若干个分组进行数据处理,比如使用聚合函数对分组进行统计。

2.1 语法

sql 复制代码
select {列 / 表达式}[,列 / 表达式...] 聚合函数(列 / 表达式) 
from 表名
group by {列 / 表达式}[,列 / 表达式...]
[having 条件]

{列 / 表达式}[,列 / 表达式...]:要查询的列或表达式,可以有多个,必须在 group by 子句中作为分组的依据;

聚合函数(列 / 表达式):列或者表达式如果不在 group by 子句中,则必须包含在聚合函数中。

2.2 示例

sql 复制代码
mysql> update books set book_type = '小说' where book_name = '阿波罗的秘密' or book_name = '另一种颜色' or book_name = '森林里有什么' or book_name = '灼烧的灵魂';
Query OK, 4 rows affected (0.07 sec)
Rows matched: 4  Changed: 4  Warnings: 0


mysql> update books set book_type = '言情' where book_name = '情书' or book_name = '22岁' or book_name = '八音盒';
Query OK, 3 rows affected (0.06 sec)
Rows matched: 3  Changed: 3  Warnings: 0


mysql> update books set book_type = '散文' where book_name = '夏日清泉' or book_name = '冬日暖阳' or book_name = 'null';
Query OK, 2 rows affected (0.06 sec)  # 影响行数只有两条,说明null并非字符串
Rows matched: 2  Changed: 2  Warnings: 0

mysql> update books set book_type = '杂志' where book_name = '马达加斯加的企鹅' or book_name = '极简主义' or book_name = null;
Query OK, 2 rows affected (0.07 sec)  # 影响行数只有两条,因为null的比较不能使用 =
Rows matched: 2  Changed: 2  Warnings: 0


# null的比较应该使用 <=>
mysql> update books set book_type = '杂志' where book_name <=> null;
Query OK, 1 row affected (0.06 sec)
Rows matched: 1  Changed: 1  Warnings: 0


mysql> select * from books;
+----+--------------------------+-----------+-------+-----------+---------------------+
| id | book_name                | author    | price | book_type | publish_date        |
+----+--------------------------+-----------+-------+-----------+---------------------+
| 29 | 阿波罗的秘密             | NULL      | 65.00 | 小说      | 2011-01-01 09:30:00 |
| 30 | 马达加斯加的企鹅         | 萨克斯    | 15.00 | 杂志      | 2013-03-12 10:30:00 |
| 31 | 极简主义                 | NULL      | 32.00 | 杂志      | 2019-04-28 00:50:00 |
| 32 | 另一种颜色               | NULL      | 32.50 | 小说      | 2019-10-01 07:10:00 |
| 33 | 夏日清泉                 | NULL      | 26.00 | 散文      | 2017-07-21 14:30:00 |
| 34 | NULL                     | NULL      | 34.00 | 杂志      | 2014-06-01 11:11:00 |
| 35 | 冬日暖阳                 | 徐然      | 46.30 | 散文      | 2019-02-28 18:11:00 |
| 36 | 22岁                     | 桂芽紫    | 55.70 | 言情      | 2018-03-21 11:11:00 |
| 37 | 森林里有什么             | NULL      | 48.00 | 小说      | 2020-05-30 08:10:00 |
| 38 | 情书                     | NULL      |  NULL | 言情      | 2010-12-01 13:30:00 |
| 39 | 八音盒                   | switch    |  NULL | 言情      | 2021-06-15 15:20:00 |
| 40 | 灼烧的灵魂               | NULL      | 62.28 | 小说      | 2021-09-01 08:35:00 |
+----+--------------------------+-----------+-------+-----------+---------------------+
12 rows in set (0.00 sec)

统计每种类别的书的数量

sql 复制代码
mysql> select book_type 类型,count(*) 数量 from books group by book_type;
+--------+--------+
| 类型   | 数量   |
+--------+--------+
| 小说   |      4 |
| 杂志   |      3 |
| 散文   |      2 |
| 言情   |      3 |
+--------+--------+
4 rows in set (0.00 sec)

统计每种类别的平均售价,最高售价,最低售价

sql 复制代码
mysql> select book_type,avg(price),max(price),min(price) from books group by book_type;
+-----------+------------+------------+------------+
| book_type | avg(price) | max(price) | min(price) |
+-----------+------------+------------+------------+
| 小说      |  51.945000 |      65.00 |      32.50 |
| 杂志      |  27.000000 |      34.00 |      15.00 |
| 散文      |  36.150000 |      46.30 |      26.00 |
| 言情      |  55.700000 |      55.70 |      55.70 |
+-----------+------------+------------+------------+
4 rows in set (0.00 sec)

使用 round(数值, 小数点位数) 指定保留多少位小数点,并添加别名优化上面的语句:

sql 复制代码
mysql> select book_type,round(avg(price),2) 平均售价,max(price) 最高售价,min(price) 最低售价 from books group by book_type;
+-----------+--------------+--------------+--------------+
| book_type | 平均售价     | 最高售价     | 最低售价     |
+-----------+--------------+--------------+--------------+
| 小说      |        51.95 |        65.00 |        32.50 |
| 杂志      |        27.00 |        34.00 |        15.00 |
| 散文      |        36.15 |        46.30 |        26.00 |
| 言情      |        55.70 |        55.70 |        55.70 |
+-----------+--------------+--------------+--------------+
4 rows in set (0.00 sec)

group by 之后还能跟 order by 子句对获得的结果集进行排序:

sql 复制代码
mysql> select book_type,round(avg(price),2) 平均售价,max(price)最高售价,min(price) 最低售价 from books group by book_type order by 平均售价 desc;
+-----------+--------------+--------------+--------------+
| book_type | 平均售价     | 最高售价     | 最低售价     |
+-----------+--------------+--------------+--------------+
| 言情      |        55.70 |        55.70 |        55.70 |
| 小说      |        51.95 |        65.00 |        32.50 |
| 散文      |        36.15 |        46.30 |        26.00 |
| 杂志      |        27.00 |        34.00 |        15.00 |
+-----------+--------------+--------------+--------------+
4 rows in set (0.00 sec)

还能统计每个类别有多少本书:

sql 复制代码
mysql> select book_type,round(avg(price),2),max(price),min(price),count(*) from books group by book_type;
+-----------+---------------------+------------+------------+----------+
| book_type | round(avg(price),2) | max(price) | min(price) | count(*) |
+-----------+---------------------+------------+------------+----------+
| 小说      |               51.95 |      65.00 |      32.50 |        4 |
| 杂志      |               27.00 |      34.00 |      15.00 |        3 |
| 散文      |               36.15 |      46.30 |      26.00 |        2 |
| 言情      |               55.70 |      55.70 |      55.70 |        3 |
+-----------+---------------------+------------+------------+----------+
4 rows in set (0.00 sec)

如果我想对分组之后的结果集进行过滤,比如找出平均售价大于50,小于55的类别,用 where 语句是错误的,而应该使用 having 子句 ↓

2.3 having

having 子句必须跟在 group by 子句后面!

sql 复制代码
mysql> select book_type,round(avg(price),2) 平均售价,max(price)最高售价,min(price) 最低售价 from books group by book_type order by 平均售价 desc having avg(price) between 50 and 55;
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 'having avg(price) between 50 and 55' at line 1
sql 复制代码
mysql> select book_type,round(avg(price),2) 平均售价,max(price)最高售价,min(price) 最低售价 from books group by book_type having avg(price) between 50 and 55 order by 平均售价 desc;
+-----------+--------------+--------------+--------------+
| book_type | 平均售价     | 最高售价     | 最低售价     |
+-----------+--------------+--------------+--------------+
| 小说      |        51.95 |        65.00 |        32.50 |
+-----------+--------------+--------------+--------------+
1 row in set (0.07 sec)

mysql> select book_type,round(avg(price),2) 平均售价,max(price)最高售价,min(price) 最低售价 from books group by book_type having avg(price) >= 50 and avg(price) <= 55 order by 平均售价 desc;
+-----------+--------------+--------------+--------------+
| book_type | 平均售价     | 最高售价     | 最低售价     |
+-----------+--------------+--------------+--------------+
| 小说      |        51.95 |        65.00 |        32.50 |
+-----------+--------------+--------------+--------------+
1 row in set (0.01 sec)

* where 子句用在 from 表名 之后,也就是分组之前,而 having 子句跟在分组 group by 之后。如果需求要求对真实数据进行过滤,同时也需要对分组的结果进行过滤,那么在合适的位置同时写 where 和 having 即可。

相关推荐
JosieBook4 小时前
【数据库】MySQL 数据库创建存储过程及使用场景详解
数据库·mysql
处女座_三月4 小时前
改 TDengine 数据库的时间写入限制
数据库·sql·mysql
酷ku的森4 小时前
Redis中的hash数据类型
数据库·redis·哈希算法
Arva .4 小时前
Redis
数据库·redis·缓存
DemonAvenger4 小时前
MySQL与应用程序的高效交互模式:从基础到实战的最佳实践
数据库·mysql·性能优化
博一波5 小时前
Redis 集群:连锁银行的 “多网点智能协作系统”
数据库·redis·缓存
HashData酷克数据5 小时前
官宣:Apache Cloudberry (Incubating) 2.0.0 发布!
数据库·开源·apache·cloudberry
秋难降5 小时前
SQL 索引突然 “罢工”?快来看看为什么
数据库·后端·sql
TDengine (老段)5 小时前
TDengine 时间函数 TODAY() 用户手册
大数据·数据库·物联网·oracle·时序数据库·tdengine·涛思数据