mysql 按关键字分组查询(MySQL基础之分组查询)
mysql 按关键字分组查询(MySQL基础之分组查询)mysql> select count(*) deptNo from emp group by deptNo; ---------- -------- | count(*) | deptNo | ---------- -------- | 2 | 1 | | 2 | 2 | | 2 | 3 | | 2 | 4 | | 2 | 5 | ---------- -------- deptNo是部门编号,所以以此列作为分组的列。前面是员工数量,后面是部门编号。可以这样写:简单分组假设有一个需求:查询每个部门的员工人数。使用count函数可以查询个数,select count(*) from emp 将整个表看作一组,返回整个表的行数。此时要求查询每个部门的员工人数,意味着要在整个emp表再按部门分组,有几个部门就分几个小组,然后再统计部门的人数。
在mysql 查询 语句中,允许使用 GROUP BY 子句对结果分组。
GROUP BY语法:
select 分组函数 列(要求在group by 子句后面) from 表名 【where 条件】 group by 分组的列 【order by 子句】
准备一个表,和一些数据。员工表,表名emp,包含姓名(ename)、工作(job)、工资(sal)、 部门编号(deptNo)等字段。
CREATE TABLE `emp` ( `id` int(255) NOT NULL AUTO_INCREMENT `ename` varchar(255) DEFAULT NULL `job` varchar(255) DEFAULT NULL `sal` int(11) DEFAULT NULL `deptNo` int(11) DEFAULT NULL `hiredate` datetime NOT NULL `bonus` int(11) DEFAULT NULL `orderNo` varchar(255) DEFAULT NULL PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8
准备好的一些测试数据
简单分组
假设有一个需求:查询每个部门的员工人数。
使用count函数可以查询个数,select count(*) from emp 将整个表看作一组,返回整个表的行数。此时要求查询每个部门的员工人数,意味着要在整个emp表再按部门分组,有几个部门就分几个小组,然后再统计部门的人数。
可以这样写:
mysql> select count(*) deptNo from emp group by deptNo; ---------- -------- | count(*) | deptNo | ---------- -------- | 2 | 1 | | 2 | 2 | | 2 | 3 | | 2 | 4 | | 2 | 5 | ---------- --------
deptNo是部门编号,所以以此列作为分组的列。前面是员工数量,后面是部门编号。
再如,查询每个部门的平均工资
mysql> select avg(sal) deptNo from emp group by deptNo; ----------- -------- | avg(sal) | deptNo | ----------- -------- | 4000.0000 | 1 | | 4100.0000 | 2 | | 3250.0000 | 3 | | 4000.0000 | 4 | | 3500.0000 | 5 | ----------- --------
有条件的分组查询
1、比如第一个问题改一下,查询每个部门有奖金的员工人数(即bonus这列,其有两个值,null和非null)
此时可以这样查
mysql> select count(*) deptNo from emp where bonus is not null group by deptNo; ---------- -------- | count(*) | deptNo | ---------- -------- | 1 | 1 | | 1 | 2 | | 1 | 3 | | 1 | 4 | | 1 | 5 | ---------- --------
奖金是筛选条件,条件涉及的字段bonus是在emp表中,也就是原始表中,此时就可以在where中使用,并且在group by 之前。
2、再有一个问题,要求查询员工人数大于1的部门。
第一步,我们可以先查出每个部门的人数
第二步,根据第一步的结果上进行筛选哪个部门员工人数大于1
查询部门员工人数 select count(*) deptNo from emp group by deptNo;
此时我们发现,根据原始表的字段,我们无法找出哪个部门的员工人数大于1,只能是根据分组之后的结果集进行筛选,此时添加条件不能在group by之前,否则会报错。
mysql> select count(*) deptNo from emp where count(*) > 1 group by deptNo; ERROR 1111 (HY000): Invalid use of group function
是group by分组之后再筛选,所以条件也在group by 子句后面,也不能再用where,而是用关键词having
mysql> select count(*) deptNo from emp group by deptNo having count(*) > 1; ---------- -------- | count(*) | deptNo | ---------- -------- | 2 | 1 | | 2 | 2 | | 2 | 3 | | 2 | 4 | | 2 | 5 | ---------- --------
筛选条件在分组前添加还是在分组后添加,可以看它能不能使用原始表中的列来确定。
分组前 原始表字段,在group by前面,用where关键词, 分组后 分组的结果集,在group by后面,用having关键词。
如果用分组函数作条件,肯定是在group by后面。
优先使用分组前筛选。
按函数分组或者表达式分组
如按员工姓名的长度进行分组,查询每个长度的员工人数。
mysql> select count(*) length(ename) from emp group by length(ename); ---------- --------------- | count(*) | length(ename) | ---------- --------------- | 4 | 4 | | 1 | 5 | | 3 | 6 | | 1 | 7 | | 1 | 8 | ---------- ---------------
按多个字段分组
如按部门、工作分组,查询员工数量
mysql> select count(*) deptNo job from emp group by deptNo job; ---------- -------- ------------- | count(*) | deptNo | job | ---------- -------- ------------- | 1 | 1 | accountant | | 1 | 1 | auditor | | 1 | 2 | cashier | | 1 | 2 | operator | | 1 | 3 | engineer | | 1 | 3 | secretary | | 1 | 4 | buyer | | 1 | 4 | electrician | | 1 | 5 | interpreter | | 1 | 5 | janitor | ---------- -------- -------------
有多个字段,加在group by后面用逗号分隔即可,两者值相同的字段才会分到一组中。字段在分组的顺序随意,没有要求。
添加排序
如查询每个部门的平均工资,按照降序排序
mysql> select avg(sal) deptNo from emp group by deptNo order by avg(sal) desc; ----------- -------- | avg(sal) | deptNo | ----------- -------- | 4100.0000 | 2 | | 4000.0000 | 4 | | 4000.0000 | 1 | | 3500.0000 | 5 | | 3250.0000 | 3 | ----------- --------
如果没有limit,order by 子句一定在查询语句的最后。