单纯使用聚合函数,无论是否包含 NULL,无论是否删除重复数据,都是针对表中的所有数据进行的汇总处理。如果需要先分组,然后在进行汇总处理。这时需要 GROUP BY 子句。

    语法:

    1. SELECT
    2. <聚合函数>,
    3. <聚合字段>
    4. FROM
    5. <表名>
    6. WHERE
    7. <筛选条件>
    8. GROUP BY
    9. <聚合字段>
    10. HAVING
    11. <分组结果对应的条件>
    12. ORDER BY
    13. <排序字段>;

    执行顺序:

    FROM —-> WHERE —-> GROUP BY —-> HAVING —-> SELECT —-> ORDER BY

    GROUP BY 子句支持单个字段和多个字段分组,各字段之间用 , 分隔。

    1. # 查询每个工种的最高工资。
    2. SELECT
    3. MAX( salary ),
    4. job_id
    5. FROM
    6. employees
    7. GROUP BY
    8. job_id;
    9. # 查询按位置分组的个数。
    10. SELECT
    11. COUNT(*),
    12. location_id
    13. FROM
    14. departments
    15. GROUP BY
    16. location_id;
    17. # 查询邮箱中包含 a 字符的,每个部门的平均工资。
    18. SELECT
    19. AVG( salary ),
    20. department_id
    21. FROM
    22. employees
    23. WHERE
    24. email LIKE '%a%'
    25. GROUP BY
    26. department_id;
    27. # 查询有奖金的每个领导手下员工的最高工资。
    28. SELECT
    29. MAX( salary ),
    30. manager_id
    31. FROM
    32. employees
    33. WHERE
    34. commission_pct IS NOT NULL
    35. GROUP BY
    36. manager_id;

    如果需要对分组后的结果进行筛选的话,这时需要 HAVING 子句。

    WHERE 子句 = 指定行所对应的条件。
    HAVING 子句 = 指定组所对应的条件。

    能够在 HAVING 子句中能够使用的 3 种要素:常数、聚合函数、GROUP BY 子句中指定的列名。

    在 WHERE 子句和 HAVING 子句中都可以使用的条件,最好写在 WHERE 子句中,这和执行的速度有关系。因为在使用聚合函数对表中的数据进行聚合操作时,DBMS 内部就会进行排序处理。排序处理会大大增加机器负担,只有尽可能减少排序的行数,才能提高处理速度。通过 WHERE 子句指定条件时, 由于排序之前就对数据进行了过滤, 因此能够减少排序的数据量。 但 HAVING 子句是在排序之后才对数据进行分组。

    另外的一个理由是可以对 WHERE 子句指定的条件创建索引。

    1. # 查询哪个部门的员工个数 > 2。
    2. # 1. 查询每个部门的员工个数。
    3. # 2. 根据 1 的结果进行筛选,员工个数 > 2。
    4. SELECT
    5. COUNT(*),
    6. department_id
    7. FROM
    8. employees
    9. GROUP BY
    10. department_id;
    11. HAVING COUNT(*) > 2;
    12. # 查询每个工种有奖金的员工的最大工资 > 12000 的工种编号和最高工资。
    13. # 1. 每个工种有奖金的员工的最高工资。
    14. # 2. 根据 1 的结果进行筛选,最高工资 > 12000。
    15. SELECT
    16. MAX( salary ),
    17. job_id
    18. FROM
    19. employees
    20. WHERE
    21. commission_pct IS NOT NULL
    22. GROUP BY
    23. job_id
    24. HAVING
    25. MAX( salary ) > 12000;
    26. # 查询领导编号 > 102 的每个领导手下的最低工资 > 5000 的领导编号是哪个。
    27. # 1. 查询每个领导手下的员工固定最低工资。
    28. # 2. 添加筛选条件,编号 > 102。
    29. # 3. 添加筛选条件,最低工资 > 5000。
    30. SELECT
    31. min( salary ),
    32. manager_id
    33. FROM
    34. employees
    35. WHERE
    36. manager_id > 102
    37. GROUP BY
    38. manager_id
    39. HAVING
    40. MIN( salary ) > 5000
    41. ORDER BY email;