#分组函数
/*
功能:用作统计使用,又称为聚合函数或统计函数或组函数
传入一组值,最后拿到一个值

分类:
sum 求和
avg 平均值
max
min
count 计算个数
*/
#1.简单使用 工资和
SELECT SUM(salary)
FROM employees;

SELECT AVG(salary)
FROM employees;

SELECT COUNT(salary)
FROM employees;

SELECT SUM(salary) 和, AVG(salary) 平均, MAX(salary) 最高, MIN(salary) 最低,COUNT(salary) 个数
FROM employees;

2.参数类型支持
SUM和AVG:数值型
MAX/MIN/COUNT:数值型、字符型、日期型、任何类型
COUNT:数值型、字符型、日期型、可以为NULL

3.是否忽略NULL
SUM/AVG:因为NULL+任何值都为NULL,所以NULL不参与运算
MAX/MIN:如果不忽略要么最小值为NULL,要么最大值为NULL,所以一定忽略
COUNT:忽略NULL值
所以都忽略NULL值

4.可以和DISTINCT搭配
SELECT SUM(DISTINCT salary),SUM(salary) FROM employees;
其他也一样,COUNT也是

5.count函数的详细介绍
SELECT COUNT(salary) FROM employees;
SELECT COUNT(*) FROM employees;#统计行数 只要任何字段有一个不为null的都会统计,所以是行数
SELECT COUNT(1) FROM employees;#107 统计1的个数,有多少行就有多少个1
也可以统计2或者其他,也就是在COUNT中加常量值来统计行数
效率:
MYISAM存储引擎下,COUNT(*)效率高
INNODB存储引擎下,COUNT(*)和COUNT(1)效率差不多,但是比里头加字段效率高,因为有筛选在里头
一般使用COUNT(*)用作统计函数

6.和分组函数一同查询的字段有限制
SELECT AVG(salary), employee_id FROM employees;
AVG完了就一个值,employee_id是一个表
#因此,和分组函数一同查询的字段要求是groud by 的字段

测试:
查询员工表中的最大入职时间和最小入职时间差的天数
SELECT DATEDIFF(MAX(hiredate), MIN(hiredate)) defference FROM employees;

查询自己活了多少天
SELECT DATEDIFF('2021-2-17','1996-11-3');

查询部门编号为90的员工个数
SELECT COUNT(*)
FROM employees
WHERE department_id = 90;
#进阶5:分组查询
#引入:查询每个部门的平均工资
SELECT AVG(salary) FROM employees;

#使用group by子句,搭配分组函数一起使用
/*
select 分组函数,列(要求出现在group by后面)
from 表
where 条件
group by 分组的列表
order by 子句

注意:查询列表必须特殊,要求是分组函数和group by后出现的字段

特点:
    1.分组查询中的筛选条件分为分类:数据源不一样
    分组前筛选: 数据源是原数据  位置在group by子句前面  where关键字
    分组后筛选: 数据源是分组后的结果集  放在group by子句后面  having关键字
    
    分组函数做条件,肯定是放在having 子句中,属于分组后筛选
    能用分组前筛选优先考虑使用!
    
    2.group by子句支持单个字段分组,也支持多个字段分组,之间用逗号隔开没有顺序要求,也支持表达式函数,但是较少
    3.也可以添加排序,排序放在整个分组查询最后!
*/
#案例1:查询每个工种的最高工资
SELECT MAX(salary),job_id
FROM employees
GROUP BY job_id;

#案例2:查询每个位置上的部门个数
SELECT COUNT(*),location_id
FROM departments
GROUP BY location_id;

#添加筛选条件
#案例3:查询邮箱中包含a字符的每个部门的平均工资
SELECT AVG(salary),department_id
FROM employees
WHERE BY email LIKE '%a%'
GROUP BY department_id;

#案例4:查询有奖金的每个领导手下员工的最高工资
SELECT MAX(salary), manager_id
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY manager_id;

#添加复杂筛选条件:添加分组后的筛选条件
#案例5:查询哪个部门的员工个数>2
#①先查询每个部门的员工个数
SELECT COUNT(*),department_id
FROM employees
GROUP BY department_id;
#②根据①的结果进行筛选
SELECT COUNT(*),department_id
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 2;

#案例6:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
#①查询每个工种有奖金的员工的最高工资
SELECT MAX(salary),job_id
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY job_id;
#②根据①的结果,查询>12000的工种编号和最高工资
SELECT MAX(salary),job_id
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY job_id
HAVING MAX(salary) > 12000;

#案例7:查询领导编号大于102的每个领导手下的最低工资大于5000的领导编号是哪个,以及最低工资
#①查询领导编号大于102的每个领导手下的员工的最低工资
SELECT MIN(salary),manager_id
FROM employees
WHERE manager_id > 102
GROUP BY manager_id;
#②根据①查询大于5000的领导编号和最低工资
SELECT MIN(salary),manager_id
FROM employees
WHERE manager_id > 102
GROUP BY manager_id
HAVING MIN(salary) > 5000;

#按表达式分组、函数分组
#案例8:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数大于5的
#①查询每个长度的员工个数
SELECT COUNT(*),LENGTH(last_name)
FROM employees
GROUP BY LENGTH(last_name);
#②添加筛选条件:筛选员工个数大于5的:分组后结果集
SELECT COUNT(*),LENGTH(last_name)
FROM employees
GROUP BY LENGTH(last_name)#支持别名
HAVING COUNT(*) > 5;#支持别名

#按多个字段分组
#案例:查询每个部门每个工种员工的平均工资
#将多个字段都一样的进行合并,否则不合并
SELECT AVG(salary),department_id,job_id
FROM employees
GROUP BY department_id,job_id;

#添加排序
#案例:查询每个部门每个工种员工的平均工资并且按工资降序排序
SELECT AVG(salary),department_id,job_id
FROM employees
WHERE department_id IS NOT NULL
GROUP BY department_id,job_id
ORDER BY AVG(salary) DESC;

#测试
#查询每个管理者手下员工的最低工资,其中最低工资不能低于6000,没有管理者的不计算在内
SELECT MIN(salary),manager_id
FROM employees
WHERE manager_id IS NOT NULL
GROUP BY manager_id
HAVING MIN(salary) >= 6000;

#查询所有部门的编号,员工数量和工资平均值,并按平均值工资降序排列
SELECT department_id,COUNT(*),AVG(salary)
FROM employees
GROUP BY department_id
ORDER BY AVG(salary) DESC;

#选择具有各个job_id的员工人数
SELECT COUNT(*),job_id
FROM employees
GROUP BY job_id;