Skip to content

聚合(聚集、分组)函数

对一组数据进行汇总的函数,输入的是一组数据的集合,输出的是单个值。

  • AVG() / SUM()

    只适用于数值类型的字段或变量 AVG,SUM 遇到 NULL 时不会计算

    sql
    SELECT AVG(salary), SUM(salary)
    FROM employees;
    
    # 0,对字符串求总值无意义。
    SELECT SUM(last_name)
    FROM employees;
  • MAX() / MIN()

    适用于数值类型、字符串类型、日期时间类型的字段或变量

    sql
    SELECT MAX(salary), MIN(salary)
    FROM employees;
    
    # Zlotkey Abel
    # 字符串比较大小有意义
    SELECT MAX(last_name), MIN(last_name)
    FROM employees;
  • COUNT()

    计算指定字段在查询结果中出现的个数

    sql
    # 107 107 107 107 107 107 107
    SELECT COUNT(employee_id), COUNT(salary), COUNT(2 * salary), COUNT(1), COUNT(2), COUNT(*)
    FROM employees;
    
    # 106,不包括 NULL
    # 因此可以推断出 AVG = SUN / COUNT
    SELECT COUNT(department_id)
    FROM employees;
    
    # 计算表中有多少条记录
    SELECT COUNT(*) FROM employees;
    SELECT COUNT(1) FROM employees;
    # 要保证该字段不为 NULL
    SELECT COUNT(具体字段) FROM employees;
    
    # 计算平均奖金率
    SELECT SUM(commission_pct) / COUNT(IFNULL(commission_pct, 0))
    # 或
    # SELECT SUM(commission_pct) / COUNT(*)
    FROM employees;
    
    # 或 
    AVG(IFNULL(commission_pct, 0))
  • GROUP BY

    sql
    # 查询各个部门的平均工资。
    SELECT department_id, AVG(salary)
    FROM employees
    GROUP BY department_id;
    
    # 查询各个 jon_id 的平均工资
    SELECT job_id, AVG(salary)
    FROM employees
    GROUP BY job_id;
    
    # 查询各个 department_id 下各个 jon_id 的平均工资
    SELECT department_id, job_id, AVG(salary)
    FROM employees
    GROUP BY department_id, job_id;
    # 或者这样写,结果是一样的。
    # GROUP BY job_id, department_id;
    
    # 错误写法,但是 8.0 不报错。
    # SELECT 中除聚合函数使用的字段外,其它字段一定要出现在 GROUP BY
    # 但 GROUP BY 中出现的字段不一定要出现在 SELECT 中。
    SELECT department_id, job_id, AVG(salary)
    FROM employees
    GROUP BY department_id;
    
    # GROUP BY 声明在 FROM 后面、WHERE 后面、ORDER BY 前面、LIMIT 前面。
    
    # WITH ROLLUP 会在结果最后增加一条记录,该记录会对 GROUP BY 后的所有分组
    # 再执行一次 ???
    # 当使用 WITH ROLLUP 时,不能使用 ORDER BY 进行排序,因为会将新增的这条记录也进行
    # 排序。
    SELECT department_id, AVG(salary), SUM(salary)
    FROM employees
    GROUP BY department_id WITH ROLLUP;
  • HAVING

    用来过滤数据,往往配合 GROUP BY 使用。

    sql
    # 查询各个部门最高工资比 10000 高的部分信息
    SELECT department_id, MAX(salary)
    FROM employees
    # 报错
    # 如果过滤条件中使用了聚合函数,必须使用 HAVING 替换 WHERE
    WHERE MAX(salary) > 10000
    GROUP BY department_id
    
    SELECT department_id, MAX(salary)
    FROM employees
    # 报错 HAVING 必须在 GROUP BY 后面
    HAVING MAX(salary) > 10000;
    GROUP BY department_id
    
    SELECT department_id, MAX(salary)
    FROM employees
    GROUP BY department_id
    HAVING MAX(salary) > 10000;
    
    # 查询部门 id 为 10, 20, 30, 404  个部门中最高工资比 10000 高的部门信息
    # 方式 1,执行效率高于方式 2,推荐。
    SELECT department_id, MAX(salary)
    FROM employees
    WHERE department_id IN (10, 20, 30, 40)
    GROUP BY department_id
    HAVING MAX(salary) > 10000;
    
    # 方式 2
    SELECT department_id, MAX(salary)
    FROM employees
    GROUP BY department_id
    HAVING MAX(salary) > 10000 
    AND department_id IN (10, 20, 30, 40);
    
    # 当过滤条件中有聚合函数时,则此过滤条件必须声明在 HAVING
    # 当过滤条件中没有聚合函数时,则此过滤条件必须声明在 WHERE 中或 HAVING 中都可以,
    # 但是建议声明在 WHERE

WHERE vs HAVING

区别1:WHERE 可以直接使用表中的字段作为筛选条件,但不能使用分组中的计算函数作为筛选条件; HAVING 必须要与 GROUP BY 配合使用,可以把分组计算的函数和分组字段作为筛选条件。 这决定了,在需要对数据进行分组统计的时候,HAVING 可以完成 WHERE 不能完成的任务。这是因为, 在查询语法结构中,WHERE 在 GROUP BY 之前,所以无法对分组结果进行筛选。HAVING 在 GROUP BY 之 后,可以使用分组字段和分组中的计算函数,对分组的结果集进行筛选,这个功能是 WHERE 无法完成 的。另外,WHERE排除的记录不再包括在分组中。 区别2:如果需要通过连接从关联表中获取需要的数据,WHERE 是先筛选后连接,而 HAVING 是先连接 后筛选。 这一点,就决定了在关联查询中,WHERE 比 HAVING 更高效。因为 WHERE 可以先筛选,用一 个筛选后的较小数据集和关联表进行连接,这样占用的资源比较少,执行效率也比较高。HAVING 则需要 先把结果集准备好,也就是用未被筛选的数据集进行关联,然后对这个大的数据集进行筛选,这样占用 的资源就比较多,执行效率也较低。 小结如下: WHERE 先筛选数据再关联,执行效率高 不能使用分组中的计算函数进行筛选 HAVING 可以使用分组中的计算函数 在最后的结果集中进行筛选,执行效率较低

开发中的选择: WHERE 和 HAVING 也不是互相排斥的,我们可以在一个查询里面同时使用 WHERE 和 HAVING。包含分组 统计函数的条件用 HAVING,普通条件用 WHERE。这样,我们就既利用了 WHERE 条件的高效快速,又发 挥了 HAVING 可以使用包含分组统计函数的查询条件的优点。当数据量特别大的时候,运行效率会有很 大的差别。