前言 🥑
在MySQL中存在一种查询方式叫做聚合查询;
聚合查询顾名思义就是将一组数据的同种类型进行聚合,那么既然是一组同类型的数据那么即必须要对该数据进行分组同时再对这组数据进行聚合;
所以对于聚合查询来说时应该有两部分组合:
- 将数据进行分组;
- 将数据进行聚合统计;
需要配合SELECT
语句进行使用;
🥝 聚合函数
在MySQL中存在一些高频操作:查询数量个数,查询数据总和…
而在MySQL中存在着一些函数,这些函数即用来对表内数据进行这些比较高频的操作,这些函数叫做聚合函数,当然这些函数存在的意义也是聚合查询中的重要操作;
存在一张表(Point)
:
+----+---------+---------+------+---------+ | id | name | chinese | math | english | +----+---------+---------+------+---------+ | 1 | Lihua | 100 | 118 | 180 | | 2 | Liming | 57 | 58 | 140 | | 3 | Zhaolao | 66 | 80 | 94 | | 4 | Wu | 76 | 70 | 94 | | 5 | Wuqi | 88 | 43 | 160 | | 6 | Liqiang | 89 | 122 | 180 | | 7 | Qinsu | 90 | 104 | 134 | | 8 | Zhaoli | 54 | 74 | 200 | +----+---------+---------+------+---------+
🍓 COUNT( ) 查询数据数量
语法:
COUNT([DISTINCT] expr) -- 返回查询到的数据的数量 -- 其中[]内为可选项
该函数能查询对应数据的数量;
- 示例1:查询该表中人数个数:
mysql> select count(*) from Point; +----------+ | count(*) | +----------+ | 8 | +----------+ 1 row in set (0.00 sec)
- 示例2:查询该表中
math
字段数据>100的个数:
mysql> select count(math) from Point where math>100; +-------------+ | count(math) | +-------------+ | 3 | +-------------+ 1 row in set (0.00 sec)
- 示例3:查询该表中
english
字段数据个数
mysql> select count(distinct english) from Point; -- 利用distinct进行去重 +-------------------------+ | count(distinct english) | +-------------------------+ | 6 | +-------------------------+ 1 row in set (0.00 sec)
🍓 SUM( ) 查询数据总和
语法:
COUNT([DISTINCT] expr)
该函数能够算出一组数据的总和;
- 示例:计算出
english
字段所有数据的总和:
mysql> select sum(english) from Point; +--------------+ | sum(english) | +--------------+ | 1182 | +--------------+ 1 row in set (0.00 sec) mysql> select sum(distinct english) from Point; +-----------------------+ | sum(distinct english) | +-----------------------+ | 908 | +-----------------------+ 1 row in set (0.00 sec)
🍓 AVG( ) 查询数据平均值
语法:
AVG([DISTINCT] expr)
该函数能够算出一组数据的平均值;
- 示例:计算出表中
english+math+chinese
字段的平均值:
mysql> select AVG(english+chinese+math) from Point; +---------------------------+ | AVG(english+chinese+math) | +---------------------------+ | 308.8750 | +---------------------------+ 1 row in set (0.00 sec)
🍓 MAX( ) 查询数据最大值
语法:
MAX([DISTINCT] expr)
该函数能够算出一组数据的最大值;
- 示例:计算出表中
chinese
字段的最大值:
mysql> select max(chinese) from Point; +--------------+ | max(chinese) | +--------------+ | 100 | +--------------+ 1 row in set (0.00 sec)
🍓 MIN( ) 查询数据最小值
语法:
MIN([DISTINCT] expr)
该函数能够算出一组数据的最小值(用法与MAX()
函数相同);
🥝 数据分组GROUP BY子句
聚合统计讲究的是一个先将数据进行分组在将数据进行聚合统计,在MySQL中可以使用GPOUP BY
子句将数据进行分组;
在SELECT
中使用GROUP BY
子句对指定列进行分组查询;
语法:
SELECT column1 ,column2, ... FROM table_name GROUP BY column1,column2...;
在进行聚合查询的演示前需要准备一个来自Oralce 9i
的测试用表 - 雇员表(该表在本篇博客中存在资源);
下载该表后使用
SOURCE /路径
的方式将表至于MySQL当中;
该文件为一个数据库,库中共有三张表: dept部门表
,emp员工表
,salgrade工资等级表
;
其中三张表的表结构分别为:
dept
Table: dept Create Table: CREATE TABLE `dept` ( `deptno` int(2) unsigned zerofill NOT NULL COMMENT ' 部门编号 ', `dname` varchar(14) DEFAULT NULL COMMENT ' 部门名称 ', `loc` varchar(13) DEFAULT NULL COMMENT ' 部门所在地点 ' ) ENGINE=MyISAM DEFAULT CHARSET=utf8
emp
Table: emp Create Table: CREATE TABLE `emp` ( `empno` int(6) unsigned zerofill NOT NULL COMMENT '雇员编号', `ename` varchar(10) DEFAULT NULL COMMENT '雇员姓名', `job` varchar(9) DEFAULT NULL COMMENT '雇员职位', `mgr` int(4) unsigned zerofill DEFAULT NULL COMMENT '雇员领导编号', `hiredate` datetime DEFAULT NULL COMMENT '雇佣时间', `sal` decimal(7,2) DEFAULT NULL COMMENT '工资月薪', `comm` decimal(7,2) DEFAULT NULL COMMENT '奖金', `deptno` int(2) unsigned zerofill DEFAULT NULL COMMENT '部门编号' ) ENGINE=MyISAM DEFAULT CHARSET=utf8
salgrade
Table: salgrade Create Table: CREATE TABLE `salgrade` ( `grade` int(11) DEFAULT NULL COMMENT '等级', `losal` int(11) DEFAULT NULL COMMENT '此等级最低工资', `hisal` int(11) DEFAULT NULL COMMENT '此等级最高工资' ) ENGINE=MyISAM DEFAULT CHARSET=utf8
该表的对应数据分别为:
############## 表dept ############## mysql> select * from dept; +--------+------------+----------+ | deptno | dname | loc | +--------+------------+----------+ | 10 | ACCOUNTING | NEW YORK | | 20 | RESEARCH | DALLAS | | 30 | SALES | CHICAGO | | 40 | OPERATIONS | BOSTON | +--------+------------+----------+ ############## 表emp ############## mysql> select * from emp; +--------+--------+-----------+------+---------------------+---------+---------+--------+ | empno | ename | job | mgr | hiredate | sal | comm | deptno | +--------+--------+-----------+------+---------------------+---------+---------+--------+ | 007369 | SMITH | CLERK | 7902 | 1980-12-17 00:00:00 | 800.00 | NULL | 20 | | 007499 | ALLEN | SALESMAN | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00 | 30 | | 007521 | WARD | SALESMAN | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00 | 30 | | 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20 | | 007654 | MARTIN | SALESMAN | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 | 30 | | 007698 | BLAKE | MANAGER | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL | 30 | | 007782 | CLARK | MANAGER | 7839 | 1981-06-09 00:00:00 | 2450.00 | NULL | 10 | | 007788 | SCOTT | ANALYST | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL | 20 | | 007839 | KING | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 | NULL | 10 | | 007844 | TURNER | SALESMAN | 7698 | 1981-09-08 00:00:00 | 1500.00 | 0.00 | 30 | | 007876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL | 20 | | 007900 | JAMES | CLERK | 7698 | 1981-12-03 00:00:00 | 950.00 | NULL | 30 | | 007902 | FORD | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL | 20 | | 007934 | MILLER | CLERK | 7782 | 1982-01-23 00:00:00 | 1300.00 | NULL | 10 | +--------+--------+-----------+------+---------------------+---------+---------+--------+ ############## 表salgrade ############## mysql> select * from salgrade; +-------+-------+-------+ | grade | losal | hisal | +-------+-------+-------+ | 1 | 700 | 1200 | | 2 | 1201 | 1400 | | 3 | 1401 | 2000 | | 4 | 2001 | 3000 | | 5 | 3001 | 9999 | +-------+-------+-------+
🍓 GROUP BY示例
- 显示每个部门的最高工资与平均工资:
该在示例中需要显示每个每个部门的最高工资,说明需要将 每个部分进行分组, 即GROUP BY deptno
;
同时要求计算出每个部门的最高工资与最低工资,说明需要对每个部门进行聚合统计,即MAX(sal)
与AVG(sal)
;
将其组合即为:
select max(sal),avg(sal) from emp group by deptno;
- 由于是以
deptno
进行分组,所以可以SELECT
出分组的名;
即:
mysql> select deptno,max(sal),avg(sal) from emp group by deptno; +--------+----------+-------------+ | deptno | max(sal) | avg(sal) | +--------+----------+-------------+ | 10 | 5000.00 | 2916.666667 | | 20 | 3000.00 | 2175.000000 | | 30 | 2850.00 | 1566.666667 | +--------+----------+-------------+
- 显示每个部门的每种岗位的平均工资与最低工资:
在该示例中需要显示每个部门与每种岗位,说明该示例中需要对数据进行两类分组,即为GROUP BY deptno , job
;
且需要聚合统计出该类数据的平均值与最高值,即为AVG(sal)
与MIN(sal)
;
在该条件中由于是对部门deptno
与岗位job
进行分组,所以在SELECT
时可以分别显示出他们的值;
即为:
mysql> SELECT deptno,job,avg(sal),min(sal) from emp group by deptno,job; +--------+-----------+-------------+----------+ | deptno | job | avg(sal) | min(sal) | +--------+-----------+-------------+----------+ | 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 | 800.00 | | 20 | MANAGER | 2975.000000 | 2975.00 | | 30 | CLERK | 950.000000 | 950.00 | | 30 | MANAGER | 2850.000000 | 2850.00 | | 30 | SALESMAN | 1400.000000 | 1250.00 | +--------+-----------+-------------+----------+ 9 rows in set (0.00 sec) # 也可将其进行重命名 mysql> SELECT deptno 部门,job 岗位,avg(sal) 最大工资,min(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 | 800.00 | | 20 | MANAGER | 2975.000000 | 2975.00 | | 30 | CLERK | 950.000000 | 950.00 | | 30 | MANAGER | 2850.000000 | 2850.00 | | 30 | SALESMAN | 1400.000000 | 1250.00 | +--------+-----------+--------------+--------------+ 9 rows in set (0.00 sec)
🍓 HAVING语句
HAVING
语句为条件筛选语句的一种,其使用方式类似于WHERE
;
大部分情况下HAVING
子句是用来配合GROUP BY
语句进行使用,即对分组聚合后的数据进行筛选;
HAVING
子句可以做到与WHERE
子句一样的事,但是WHERE
子句的功能却不能与HAVING
子句相当;
由于HAVING
语句是用来针对聚合统计而产生的,所以在MySQL中不能使用HAVING
子句来代替WHERE
子句,即这两个语句不能混为一谈;
- 示例:显示平均工资低于2000的部门和它的平均工资:
在该示例中要求了平均工资低于2000的部门
,即需要对部门进行GROUP BY
分类,即GROUP BY deptno
;
同时示例要求显示平均工资,即为AVG(sal)
;
将其组合在一起即能显示出各个部门的平均工资:
mysql> select deptno,avg(sal) from emp group by deptno; +--------+-------------+ | deptno | avg(sal) | +--------+-------------+ | 10 | 2916.666667 | | 20 | 2175.000000 | | 30 | 1566.666667 | +--------+-------------+ 3 rows in set (0.00 sec)
- 其又要求显示平均工资低于2000的部门与它的平均工资,则可以使用
HAVING
子句对聚合统计后的数据进行筛选;
mysql> select deptno as 部门,avg(sal) as 平均工资 from emp group by deptno having 平均工资<2000; +--------+--------------+ | 部门 | 平均工资 | +--------+--------------+ | 30 | 1566.666667 | +--------+--------------+ 1 row in set (0.00 sec) ##当使用where子句代替having子句时将会报错; mysql> select deptno as 部门,avg(sal) as 平均工资 from emp group by deptno where 平均工资<2000; 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 平均工资<2000' at line 1