单纯使用聚合函数,无论是否包含 NULL,无论是否删除重复数据,都是针对表中的所有数据进行的汇总处理。如果需要先分组,然后在进行汇总处理。这时需要 GROUP BY 子句。
语法:
SELECT<聚合函数>,<聚合字段>FROM<表名>WHERE<筛选条件>GROUP BY<聚合字段>HAVING<分组结果对应的条件>ORDER BY<排序字段>;
执行顺序:
FROM —-> WHERE —-> GROUP BY —-> HAVING —-> SELECT —-> ORDER BY
GROUP BY 子句支持单个字段和多个字段分组,各字段之间用 , 分隔。
# 查询每个工种的最高工资。SELECTMAX( salary ),job_idFROMemployeesGROUP BYjob_id;# 查询按位置分组的个数。SELECTCOUNT(*),location_idFROMdepartmentsGROUP BYlocation_id;# 查询邮箱中包含 a 字符的,每个部门的平均工资。SELECTAVG( salary ),department_idFROMemployeesWHEREemail LIKE '%a%'GROUP BYdepartment_id;# 查询有奖金的每个领导手下员工的最高工资。SELECTMAX( salary ),manager_idFROMemployeesWHEREcommission_pct IS NOT NULLGROUP BYmanager_id;
如果需要对分组后的结果进行筛选的话,这时需要 HAVING 子句。
WHERE 子句 = 指定行所对应的条件。
HAVING 子句 =  指定组所对应的条件。
能够在 HAVING 子句中能够使用的 3 种要素:常数、聚合函数、GROUP BY 子句中指定的列名。
在 WHERE 子句和 HAVING 子句中都可以使用的条件,最好写在 WHERE 子句中,这和执行的速度有关系。因为在使用聚合函数对表中的数据进行聚合操作时,DBMS 内部就会进行排序处理。排序处理会大大增加机器负担,只有尽可能减少排序的行数,才能提高处理速度。通过 WHERE 子句指定条件时, 由于排序之前就对数据进行了过滤, 因此能够减少排序的数据量。 但 HAVING 子句是在排序之后才对数据进行分组。
另外的一个理由是可以对 WHERE 子句指定的条件创建索引。
# 查询哪个部门的员工个数 > 2。# 1. 查询每个部门的员工个数。# 2. 根据 1 的结果进行筛选,员工个数 > 2。SELECTCOUNT(*),department_idFROMemployeesGROUP BYdepartment_id;HAVING COUNT(*) > 2;# 查询每个工种有奖金的员工的最大工资 > 12000 的工种编号和最高工资。# 1. 每个工种有奖金的员工的最高工资。# 2. 根据 1 的结果进行筛选,最高工资 > 12000。SELECTMAX( salary ),job_idFROMemployeesWHEREcommission_pct IS NOT NULLGROUP BYjob_idHAVINGMAX( salary ) > 12000;# 查询领导编号 > 102 的每个领导手下的最低工资 > 5000 的领导编号是哪个。# 1. 查询每个领导手下的员工固定最低工资。# 2. 添加筛选条件,编号 > 102。# 3. 添加筛选条件,最低工资 > 5000。SELECTmin( salary ),manager_idFROMemployeesWHEREmanager_id > 102GROUP BYmanager_idHAVINGMIN( salary ) > 5000ORDER BY email;
