目录
一、聚合函数
1.1 count
1.1.1 统计整张表中所有记录的总条数
1.1.2 统计单列的数据
1.1.3 统计单列记录+限制条件
1.2 sum
1.3 avg
1.4 max, min
二、group by 分组查询
2.1 语法
2.2 示例
2.3 having
一、聚合函数
常用的聚合函数
函数 | 说明 |
---|---|
count ([distinct] expr) | 返回查询到的数据的数量 |
sum ([distinct] expr) | 返回查询到的数据的总和,不是数字的没有意义 |
avg ([distinct] expr) | 返回查询到的数据的平均值,非数字无意义 |
max ([distinct] expr) | 返回查询到的数据的最大值,非数字无意义 |
min ([distinct] expr) | 返回查询到的数据的最小值,非数字无意义 |
1.1 count
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 表中有多少条记录:
mysql> select count(*) from books;
+----------+
| count(*) |
+----------+
| 12 |
+----------+
1 row in set (0.01 sec)
② 使用常量做统计
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 值不被计入结果集中
mysql> select count(author) from books;
+---------------+
| count(author) |
+---------------+
| 4 |
+---------------+
1 row in set (0.00 sec)
1.1.3 统计单列记录+限制条件
统计价格小于40的图书数量
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 的数据行不参与统计
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
括号里面可以是单列数据,也可以是多列数据
-- 单列统计平均值
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 最低值
# 多个聚合函数可以同时被使用
mysql> select max(power),min(intelligence) from game;
+------------+-------------------+
| max(power) | min(intelligence) |
+------------+-------------------+
| 100 | 50 |
+------------+-------------------+
1 row in set (0.00 sec)
# 使用别名
mysql> select max(power) 最高力量值,min(intelligence) '最低智力值' from game;
+-----------------+-----------------+
| 最高力量值 | 最低智力值 |
+-----------------+-----------------+
| 100 | 50 |
+-----------------+-----------------+
1 row in set (0.00 sec)
# 同一列可以使用不同聚合函数
mysql> select max(power) 最高力量值,min(power) 最低力量值 from game;
+-----------------+-----------------+
| 最高力量值 | 最低力量值 |
+-----------------+-----------------+
| 100 | 50 |
+-----------------+-----------------+
1 row in set (0.00 sec)
二、group by 分组查询
group by 子句的作用是通过⼀定的规则将⼀个数据集划分成若干个小的分组,然后针对若干个分组进行数据处理,比如使用聚合函数对分组进行统计。
2.1 语法
select {列 / 表达式}[,列 / 表达式...] 聚合函数(列 / 表达式)
from 表名
group by {列 / 表达式}[,列 / 表达式...]
[having 条件]
{列 / 表达式}[,列 / 表达式...]:要查询的列或表达式,可以有多个,必须在 group by 子句中作为分组的依据;
聚合函数(列 / 表达式):列或者表达式如果不在 group by 子句中,则必须包含在聚合函数中。
2.2 示例
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: 0mysql> 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: 0mysql> 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: 0mysql> 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: 0mysql> 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)
统计每种类别的书的数量
mysql> select book_type 类型,count(*) 数量 from books group by book_type;
+--------+--------+
| 类型 | 数量 |
+--------+--------+
| 小说 | 4 |
| 杂志 | 3 |
| 散文 | 2 |
| 言情 | 3 |
+--------+--------+
4 rows in set (0.00 sec)
统计每种类别的平均售价,最高售价,最低售价
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(数值, 小数点位数) 指定保留多少位小数点,并添加别名优化上面的语句:
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 子句对获得的结果集进行排序:
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)
还能统计每个类别有多少本书:
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 子句后面!
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
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 即可。