MySQL之聚合查询、分组和函数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lk142500/article/details/83316876

1 简介

之前写过一个比较单表查询比较简单的内容。在单表查询查询中,还有较为高级的部分,诸如聚合查询,排序和分组查询,熟悉的了解关系型数据库中此类操作,可以非常方便的帮助我们实现自定义的数据提取操作。单表查询的简单查询内容可以参见

https://blog.csdn.net/lk142500/article/details/82728889

2 材料

因为所有的数据库管理系统的底层均为命令行,只不过提供界面之后更加的直观和容易操作,为了基础,仍以命令行为工具,查询不同命令的输入和输出结果,以期增加对关系型数据库的理解和使用。
楼主使用的数据库为MySQL 8.0.11

3 操作记录

单表操作的主要使用语句为SELECT语句,在SELECT语句中,可以根据自己对数据的需求,使用不同的查询条件,基本语法格式如下:

SELECT  [DISTINCT] *|{字段名1, 字段名2, 字段名3,……}
                       FROM 表名
	         [WHERE 条件表达式1]
	         [GROUP BY 字段名 [HAVING 条件表达式2]]
	         [ORDER BY 字段名 [ASC|DESC]]
	         [LIMIT [OFFSET] 记录数]

3.1 产生数据

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| act                |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
mysql> create database test
    -> ;
Query OK, 1 row affected (0.20 sec)
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| act                |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
6 rows in set (0.00 sec)

使用数据库test,并在数据库中产生表student

mysql> use test;
Database changed
mysql> create table student(
    -> id INT(3) PRIMARY KEY AUTO_INCREMENT,
    -> name varchar(20) not null,
    -> grade float,
    -> gender CHAR(2)
    -> );
Query OK, 0 rows affected (0.51 sec)

mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| student        |
+----------------+
1 row in set (0.00 sec)

使用insert语句向表student中插入8条数据
mysql> insert into student (name, grade, gender)
-> VALUES (“songjiang”, 40, ‘男’),
-> (“wuyong”, 100, ‘男’),
-> (“qinming”, 90, ‘男’),
-> (“husanniang”, 80, ‘男’),
-> (“sunerniang”, 66, ‘男’),
-> (“wusong”, 86, ‘男’),
-> (“linchong”, 92, ‘男’),
-> (“yanqing”, 90, ‘男’);
Query OK, 8 rows affected (0.19 sec)
Records: 8 Duplicates: 0 Warnings: 0

3.2 聚合函数

实际开发中,经常需要对某些数据进行统计,例如统计某个字段的最大值,最小值,平均值等,为了实现这些功能,MySQL提供了一些函数来实现这些功能。

3.2.1 COUNT()

COUNT函数用来统计记录的条数,语法格式如下:

select COUNT(*) from 表名

统计student表中记录数

mysql> select * from student;
+----+------------+-------+--------+
| id | name       | grade | gender |
+----+------------+-------+--------+
|  1 | songjiang  |    40 | 男     |
|  2 | wuyong     |   100 | 男     |
|  3 | qinming    |    90 | 男     |
|  4 | husanniang |    80 | 男     |
|  5 | sunerniang |    66 | 男     |
|  6 | wusong     |    86 | 男     |
|  7 | linchong   |    92 | 男     |
|  8 | yanqing    |    90 | 男     |
+----+------------+-------+--------+
8 rows in set (0.05 sec)

mysql> select count(*) from student;
+----------+
| count(*) |
+----------+
|        8 |
+----------+
1 row in set (0.05 sec)

为查询到的记录总数起个别名

扫描二维码关注公众号,回复: 3738733 查看本文章
mysql> select count(*) as records from student;
+---------+
| records |
+---------+
|       8 |
+---------+
1 row in set (0.00 sec)

mysql> select count(*) records from student;
+---------+
| records |
+---------+
|       8 |
+---------+
1 row in set (0.00 sec)

3.2.2 SUM()

sum是求和函数,用于求出表中某个字段所有值的总和,语法如下:

select sum(字段名) from 表名

使用该语句可以求出指定字段值的总和
求出student表中grade成绩的总和

mysql> select sum(grade) 成绩总和 from student;
+--------------+
| 成绩总和     |
+--------------+
|          644 |
+--------------+
1 row in set (0.01 sec)

3.2.3 AVG()

AVG可以用于求出某个字段所有值得平均值

select avg(字段名) from student;


mysql> select avg(grade)  from student;
+------------+
| avg(grade) |
+------------+
|       80.5 |
+------------+
1 row in set (0.00 sec)

3.2.4 MAX/min
max/min函数则是用于求最大值/最小值的函数,用于求出某个字段的最大值

mysql> select max(grade) from student;
+------------+
| max(grade) |
+------------+
|        /100 |
+------------+
1 row in set (0.00 sec)

mysql> select min(grade) from student;
+------------+
| min(grade) |
+------------+
|         40 |
+------------+
1 row in set (0.00 sec)

3.3 对查询结果进行排序
从表中查询出来的数据可能是无序的,或者其排列顺序不是用户预期的。为了使查询结果满足用户的要求,可以使用ORDER BY对查询结果进行排序,语法格式如下:

SELECT 字段名1,字段名2,……
FROM 表名
ORDER BY 字段名1 [ASC | DESC],字段名2 [ASC | DESC]……

查询student表中的所有记录,按照grade进行排序

mysql> select * from student order by grade;
+----+------------+-------+--------+
| id | name       | grade | gender |
+----+------------+-------+--------+
|  1 | songjiang  |    40 | 男     |
|  5 | sunerniang |    66 | 男     |
|  4 | husanniang |    80 | 男     |
|  6 | wusong     |    86 | 男     |
|  3 | qinming    |    90 | 男     |
|  8 | yanqing    |    90 | 男     |
|  7 | linchong   |    92 | 男     |
|  2 | wuyong     |   100 | 男     |
+----+------------+-------+--------+
8 rows in set (0.00 sec)

mysql> select * from student order by grade ASC;
+----+------------+-------+--------+
| id | name       | grade | gender |
+----+------------+-------+--------+
|  1 | songjiang  |    40 | 男     |
|  5 | sunerniang |    66 | 男     |
|  4 | husanniang |    80 | 男     |
|  6 | wusong     |    86 | 男     |
|  3 | qinming    |    90 | 男     |
|  8 | yanqing    |    90 | 男     |
|  7 | linchong   |    92 | 男     |
|  2 | wuyong     |   100 | 男     |
+----+------------+-------+--------+
8 rows in set (0.00 sec)

mysql>

从查询结果可以看到,返回的记录按照order by指定的字段进行排序,并且默认是升序的。两次查询的结果是一只的。
按照grade 逆序排列

mysql> select * from student order by grade desc;
+----+------------+-------+--------+
| id | name       | grade | gender |
+----+------------+-------+--------+
|  2 | wuyong     |   100 | 男     |
|  7 | linchong   |    92 | 男     |
|  3 | qinming    |    90 | 男     |
|  8 | yanqing    |    90 | 男     |
|  6 | wusong     |    86 | 男     |
|  4 | husanniang |    80 | 男     |
|  5 | sunerniang |    66 | 男     |
|  1 | songjiang  |    40 | 男     |
+----+------------+-------+--------+
8 rows in set (0.00 sec)

更新student表中yanqing行性别为NULL

mysql> update student set gender=NULL where name='yanqing';
Query OK, 1 row affected (0.15 sec)
Rows matched: 1  Changed: 1  Warnings: 0

在MySQL中,可以指定按照多个字段对查询结果进行排序。例如按照gender和grade字段进行排序,按照gender字段升序排列,按照grade字段降序排列

mysql> select * from student order by gender asc, grade desc;
+----+------------+-------+--------+
| id | name       | grade | gender |
+----+------------+-------+--------+
|  8 | yanqing    |    90 | NULL   |
|  4 | husanniang |    80 | 女     |
|  5 | sunerniang |    66 | 女     |
|  2 | wuyong     |   100 | 男     |
|  7 | linchong   |    92 | 男     |
|  3 | qinming    |    90 | 男     |
|  6 | wusong     |    86 | 男     |
|  1 | songjiang  |    40 | 男     |
+----+------------+-------+--------+
8 rows in set (0.00 sec)

上述的命令使得记录按照多个字段进行排序,可以看到输出的记录先按照gender进行升序排列,相同的gender,则按照grade逆序排列。

3.4 分组查询

在对表中数据进行统计时,也可能需要按照一定的类别进行统计,比如,分别统计student表中gender字段为“男” “女“, “NULL”的学生成绩之和。在mysql中,可以使用group by按某个字段或者多个字段中的值进行分组,字段中值相同的为1组,其语法格式如下:

SELECT 字段名1,字段名2,……
     FROM 表名
     GROUP BY 字段名1,字段名2,……[HAVING 条件表达式];

HAVING关键字指定条件表达式对分组后的内容进行过滤。需要注意的是,Group BY一般和聚合函数一起使用,如果查询的字段出现在Group By后,却没有包含在聚合函数中,该字段显示的是分组后第一条记录的值,这样可能会导致查询的结果与预期不符合。

3.4.1 单独使用Group By进行分组

mysql> select * from student group by gender;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.stude
nt.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_g
roup_by
mysql> select * from student group by id;
+----+------------+-------+--------+
| id | name       | grade | gender |
+----+------------+-------+--------+
|  1 | songjiang  |    40 | 男     |
|  2 | wuyong     |   100 | 男     |
|  3 | qinming    |    90 | 男     |
|  4 | husanniang |    80 | 女     |
|  5 | sunerniang |    66 | 女     |
|  6 | wusong     |    86 | 男     |
|  7 | linchong   |    92 | 男     |
|  8 | yanqing    |    90 | NULL   |
+----+------------+-------+--------+
8 rows in set (0.00 sec)

mysql> select count(*), gender from student group by gender;
+----------+--------+
| count(*) | gender |
+----------+--------+
|        5 | 男     |
|        2 | 女     |
|        1 | NULL   |
+----------+--------+
3 rows in set (0.00 sec)

3.4.2 Group By和聚合函数一起使用
Group BY和聚合函数一起使用,可以统计处某个或者某些字段在一个分组中的最大值,最小值,平均值。
将student表按照gender字段值进行分组查询,计算出每个分组有多少个学生

mysql> select count(*), gender from student group by gender;
+----------+--------+
| count(*) | gender |
+----------+--------+
|        5 | 男     |
|        2 | 女     |
|        1 | NULL   |
+----------+--------+
3 rows in set (0.00 sec)

从查询结果可以看出,group by对student表按照gender字段中不同的值进行了分组,并通过count函数统计出每个分组的个数。

3.4.3 Group By和Having关键字一起使用

Having关键字与where字句作用相同,都用于设置条件表达式对查询结果进行过滤,两者的区别在于,Having关键字后可以跟聚合函数,而where子句不可以。通常情况先Having关键字都和Group By一起使用,用于对分组后的结果进行过滤。
将student表中按照gender字段进行分组排序,查询出grade字段值之和小于300的分组

mysql> select sum(grade), gender from student group by gender having sum(grade)<300;
+------------+--------+
| sum(grade) | gender |
+------------+--------+
|        146 | 女     |
|         90 | NULL   |
+------------+--------+
rows in set (0.06 sec)

对gender值为’男’的所有学生其grade字段值之和进行查询

    mysql> select sum(grade), gender from student where gender='男';
    +------------+--------+
    | sum(grade) | gender |
    +------------+--------+
    |        408 | 男     |
    +------------+--------+
    1 row in set (0.00 sec )

3.5 使用LIMIT限制查询结果的数量

查询数据时,可能会返回很多数据,而用户需要的记录可能只是其中的一条或者几条,比如实现分页功能,每页显示十条数据,每次查询就只需要十条数据。为此,MySQL提供了LIMIT关键字,可以指定查询结果从那一条记录开始,以及一共查询多少条信息,语法格式如下:

SELECT 字段名1,字段名2,……
FROM 表名
LIMIT [OFFSET,] 记录数

LIMIT:后面可以跟2个参数,“OFFSET”:为可选值,表示偏移量,如果偏移量为0则从查询结果的第一条记录开始…以此类推,如果不指定其默认值为0。
“记录数”:表示返回查询记录的条数。
查询表student的前四条数据

mysql> select * from student limit 4
    -> ;
+----+------------+-------+--------+
| id | name       | grade | gender |
+----+------------+-------+--------+
|  1 | songjiang  |    40 | 男     |
|  2 | wuyong     |   100 | 男     |
|  3 | qinming    |    90 | 男     |
|  4 | husanniang |    80 | 女     |
+----+------------+-------+--------+
4 rows in set (0.00 sec)

查询student表中grade字段值从第5到第8位的学生,从高到底

mysql> select * from student order by grade desc limit 4, 4;
+----+------------+-------+--------+
| id | name       | grade | gender |
+----+------------+-------+--------+
|  6 | wusong     |    86 | 男     |
|  4 | husanniang |    80 | 女     |
|  5 | sunerniang |    66 | 女     |
|  1 | songjiang  |    40 | 男     |
+----+------------+-------+--------+
rows in set (0.00 sec)

注意:LIMIT后跟了两个参数,两个参数以逗号隔开,第一个参数表示偏移量为4,即从第五条记录开始查询,第二个参数表示一共返回4条数据,即从第五到第八位。是哟个ORDER BY DESC使学生记录按照grade字段从高到低的顺序进行排列。
显示所有student记录,以grade排序,逆序

mysql> select * from student order by grade desc;
+----+------------+-------+--------+
| id | name       | grade | gender |
+----+------------+-------+--------+
|  2 | wuyong     |   100 | 男     |
|  7 | linchong   |    92 | 男     |
|  3 | qinming    |    90 | 男     |
|  8 | yanqing    |    90 | NULL   |
|  6 | wusong     |    86 | 男     |
|  4 | husanniang |    80 | 女     |
|  5 | sunerniang |    66 | 女     |
|  1 | songjiang  |    40 | 男     |
+----+------------+-------+--------+
8 rows in set (0.00 sec)

3.6 函数(列表)

MySQL中提供了丰富的函数,通过这些函数可以简化用户对数据的操
作,MySQL中的函数包括数学函数,字符串函数,日期和时间函数条件判断函数,加密函数,由于函数较多,不一一讲解。

3.6.1 数学函数

函数名称 作用
ABS(x) 绝对值
SQRT(x) 返回x的非负二次方根
MOD(x, y) 返回x被y除后的余数
FLOOR(x) 返回不大于x的最大整数
ROUND(x, y) 对x进行四舍五入整数,小数点保持y位
TRUNCATE(x, y) 舍去x中小数点y位后面的数
SIGN(x) 返回x的符号,-1, 0, 1

3.6.2 字符串函数

函数 作用
length(str) 返回str的长度
concat(s1, s2,…) 返回一个或者多个字符串连接产生的新字符串
trim(str) 删除字符串两侧的空格
replace(str, s1, s2) 使用字符串s2替换字符串str中所有的字符串s1
substring(str, n, len) 返回字符串str的子串,起始位置为n,长度为len
reverse(str) 返回字符串反转后的结果
locate(s1, str) 返回字符串s1在字符串str中的起始位置。

3.6.3 日期和时间函数

函数 作用
curdate() 获取当前日期
curtime() 获取当前时间
sysdate() 获取当前系统日期和时间
time_to_sec() 返回将时间转换成秒的结果
adddate() 执行日期的加运算
subdate() 执行日期的减运算
date_format() 格式化输出日期和时间值

3.6.4 条件判断 函数

函数 作用
IF(expr, v1, v2) 如果表达式expr为true,返回v1,否则v2
IFNULL(v1, v2) 如果v1不为NULL,返回v1,否则返回v2
CASE expr when v1 then r1 [when v2 then r2…] else rn end 如果expr的值等于v1,v2等值,则返回对应位置的then之后的结果,否则返回else之后的结果

3.6.5 加密函数

函数 作用
MD5(str) 对字符串str进行MD5加密
Encode(str, pwd_str) 使用pwd作为密码加密字符串str
decode(str, pwd_str) 使用pwd作为密码解密字符串str

查询student表中所有记录,将各个字段值使用下划线”_”连接起来

mysql> select concat(id, "_", name, "_", grade, "_", gender) from student;
+------------------------------------------------+
| concat(id, "_", name, "_", grade, "_", gender) |
+------------------------------------------------+
| 1_songjiang_40_男                              |
| 2_wuyong_100_男                                |
| 3_qinming_90_男                                |
| 4_husanniang_80_女                             |
| 5_sunerniang_66_女                             |
| 6_wusong_86_男                                 |
| 7_linchong_92_男                               |
| NULL                                           |
+------------------------------------------------+
8 rows in set (0.00 sec)

查询student表中的id和gender值,如果gender为男,则返回1否则返回0

mysql> select id, if(gender='男', 1, 0) from student;
+----+------------------------+
| id | if(gender='男', 1, 0)  |
+----+------------------------+
|  1 |                      1 |
|  2 |                      1 |
|  3 |                      1 |
|  4 |                      0 |
|  5 |                      0 |
|  6 |                      1 |
|  7 |                      1 |
|  8 |                      0 |
+----+------------------------+
8 rows in set (0.00 sec)

4 为表和字段取别名

4.1 为表取别名

在查询数据时,可以为表和字段取别名,这个别名可以代替指定的表和字段。如果表名很长,用起来不方便,则可以用一个别名来代替,语法如下:

select * from 表名 [as] 别名

as关键字可以省略。
如下例子所示:

mysql> select * from student as s where s.gender='女';
+----+------------+-------+--------+
| id | name       | grade | gender |
+----+------------+-------+--------+
|  4 | husanniang |    80 | 女     |
|  5 | sunerniang |    66 | 女     |
+----+------------+-------+--------+
2 rows in set (0.00 sec)

mysql> select * from student s where s.gender='女';
+----+------------+-------+--------+
| id | name       | grade | gender |
+----+------------+-------+--------+
|  4 | husanniang |    80 | 女     |
|  5 | sunerniang |    66 | 女     |
+----+------------+-------+--------+
2 rows in set (0.00 sec)

4.2 为字段取别名

SELECT 字段名 [AS] 别名[,字段名 [AS] 别名,……] FROM 表名;

如例子:

mysql> select name as stu_name, gender stu_gender from student;
+------------+------------+
| stu_name   | stu_gender |
+------------+------------+
| songjiang  | 男         |
| wuyong     | 男         |
| qinming    | 男         |
| husanniang | 女         |
| sunerniang | 女         |
| wusong     | 男         |
| linchong   | 男         |
| yanqing    | NULL       |
+------------+------------+
8 rows in set (0.00 sec)

5 总结

本文主要是简要讲述了Mysql中单表的高级查询,通过熟练掌握命令行操作,可以加深对mysql的基本使用,对于关系型数据库的理解非常有助。在Java spring对数据库的增删改查操作时,使用的是同样的原理。

6 参考

https://blog.csdn.net/lk142500/article/details/82728889
https://download.csdn.net/download/lk142500/10740289
传智博客MySQL数据库入门

猜你喜欢

转载自blog.csdn.net/lk142500/article/details/83316876