MySQL 08 章——聚合函数

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

一、聚合函数介绍

(1)AVG和SUM函数

  1. 举例:
  2. 只适用于数值类型的字段(或变量)
  3. AVG函数和SUM函数在计算空值时,会自动把NULL过滤掉

(2)MIN和MAX函数

  1. 举例:
  2. 适用于数值类型、字符串类型、日期时间类型的字段(变量)

(3)COUNT函数

  1. 举例:
  2. 作用:计算指定字段在查询结构中出现的个数,如果值为NULL就不会被计算进去
  3. 如果计算表中有多少条记录,如何实现?
    1. COUNT(*)
    2. COUNT(1)
    3. COUNT(具体字段):不一定对!因为字段中的NULL值不会被计算进去
  4. AVG = SUM / COUNT,因为这三个函数都过滤掉了NULL值,所以
  5. 需求:查询公司中的平均奖金率
  6. 如果需要统计表中的记录数,使用COUNT(*)、COUNT(1)、COUNT(具体字段)哪个效率更高呢?
    1. 如果使用的是MyISAM存储引擎,则三者的效率相同,都是O(1)
    2. 如果使用的是InnoDB存储引擎,则三者效率:COUNT(*) = COUNT(1) > COUNT(具体字段)

二、GROUP BY

(1)基本使用

  1. 需求:查询各个部门的平均工资、最高工资

(2)使用多个列分组

  1. 需求:查询各个部门中,各个工种的平均工资
  2. 注意:SELECT中出现的非聚合函数的字段,必须声明在GROUP BY中;反之,GROUP BY中声明的字段可以不出现在SELECT中
  3. GROUP BY声明在FROM后面,WHERE后面,ORDER BY前面,LIMIT前面

(3)GROUP BY中使用WITH ROLLUP

  1. 使用WITH ROLLUP关键字之后,在所有查询出的记录之后,增加了一条记录。该记录就是汇总行
  2. 当使用WITH ROLLUP时,不能同时使用ORDER BY子句进行结果排序,即WITH ROLLUP和ORDER BY是相互排斥的

三、HAVING

(1)基本使用

  1. HAVING的作用:是用来过滤数据的
  2. 练习:查询各个部门中最高工资比10000高的部门信息
  3. 如果过滤条件中使用了聚合函数,则必须用HAVING来替换WHERE,否则报错
  4. HAVING必须声明在GROUP BY的后面
  5. 开发中,使用HAVING的前提是使用了GROUP BY

(2)WHERE和HAVING的对比

  1. 练习:查询部门id为10,20,30,40这4个部门中最高工资比10000高的部门信息(两种方式)
  2. 推荐使用方式一,执行效率高于方式二
  3. 当过滤条件中有聚合函数时,则此过滤条件必须声明在HAVING中。当过滤条件中没有聚合函数时,则此过滤条件声明在HAVING或WHERE中都可以。但是建议声明在WHERE中,效率更高
  4. WHERE和HAVING对比:
    1. 从适用范围上来讲,HAVING的适用范围更广
    2. 如果过滤条件中没有聚合函数,这种情况下,WHERE的效率要高于HAVING

四、SELECT的执行过程

(1)查询的结构

  1. sql92语法:

    sql 复制代码
    SELECT ...,...,...(存在聚合函数)
    FROM ...,...,...
    WHERE 多表的连接条件 AND 不包含聚合函数的过滤条件
    GROUP BY ...,...
    HAVING 包含聚合函数的过滤条件
    ORDER BY ...,...(ASC/DESC)
    LIMIT ...,...
  2. sql99语法:

    sql 复制代码
    SELECT ...,...,...(存在聚合函数)
    FROM ...(LEFT / RIGHT)JOIN...ON 多表的连接条件
    JOIN...ON 多表的连接条件
    WHERE 不包含聚合函数的过滤条件
    GROUP BY ...,...
    HAVING 包含聚合函数的过滤条件
    ORDER BY ...,...(ASC/DESC)
    LIMIT ...,...

(2)SELECT执行顺序

  1. FROM ...JOIN...,先对两张表进行笛卡尔积。ON用来去掉不应该关联的数据
  2. 关注左外连接和右外连接
  3. WHERE过滤数据
  4. 对过滤后的数据进行分组(GROUP BY),然后执行HAVING
  5. SELECT选出字段
  6. ORDER BY排序,然后分页查询

(3)SQL的执行原理

  1. SELECT 是先执行 FROM 这一步的。在这个阶段,如果是多张表联查,还会经历下面的几个步骤:
    (1)首先先通过 CROSS JOIN 求笛卡尔积,相当于得到虚拟表 vt(virtual table)1-1
    (2)通过 ON 进行筛选,在虚拟表 vt1-1 的基础上进行筛选,得到虚拟表 vt1-2
    (3)添加外部行。如果我们使用的是左连接、右链接或者全连接,就会涉及到外部行,也就是在虚拟表 vt1-2 的基础上增加外部行,得到虚拟表 vt1-3
    (4)当然如果我们操作的是两张以上的表,还会重复上面的步骤,直到所有表都被处理完为止。这个过程得到是我们的原始数据

  2. 当我们拿到了查询数据表的原始数据,也就是最终的虚拟表 vt1,就可以在此基础上再进行 WHERE 阶段。在这个阶段中,会根据 vt1 表的结果进行筛选过滤,得到虚拟表 vt2

  3. 然后进入第三步和第四步,也就是 GROUP 和 HAVING 阶段。在这个阶段中,实际上是在虚拟表 vt2 的基础上进行分组和分组过滤,得到中间的虚拟表 vt3 和 vt4

  4. 当我们完成了条件筛选部分之后,就可以筛选表中提取的字段,也就是进入到 SELECT 和 DISTINCT 阶段。首先在 SELECT 阶段会提取想要的字段,然后在 DISTINCT 阶段过滤掉重复的行,分别得到中间的虚拟表 vt5-1 和 vt5-2

  5. 当我们提取了想要的字段数据之后,就可以按照指定的字段进行排序,也就是 ORDER BY 阶段,得到虚拟表 vt6

  6. 最后在 vt6 的基础上,取出指定行的记录,也就是 LIMIT 阶段,得到最终的结果,对应的是虚拟表 vt7

  7. 当然我们在写 SELECT 语句的时候,不一定存在所有的关键字,相应的阶段就会省略

五、课后练习

  1. 查询公司员工工资的最大值、最小值、平均值、总和

    sql 复制代码
    SELECT MAX(salary),MIN(salary),AVG(salary),SUM(salary)
    FROM employees;
  2. 查询各job_id的员工工资的最大值、最小值、平均值、总和

    sql 复制代码
    SELECT job_id,MAX(salary),MIN(salary),AVG(salary),SUM(salary)
    FROM employees
    GROUP BY job_id;
  3. 选择具有各个job_id的员工人数

    sql 复制代码
    SELECT job_id,COUNT(*) "workers"
    FROM employees
    GROUP BY job_id;
  4. 查询员工最高工资和最低工资的差距(DIFFERENCE)

    sql 复制代码
    SELECT MAX(salary) - MIN(salary) "DIFFERENCE"
    FROM employees;
  5. 查询各个管理者手下员工的最低工资,其中最低工资不能低于6000,没有管理者的员工不计算在内

    sql 复制代码
    SELECT manager_id,MIN(salary)
    FROM employees
    WHERE manager_id IS NOT NULL
    GROUP BY manager_id
    HAVING MIN(salary) >= 6000;
  6. 查询所有部门的名字,location_id,员工数量和平均工资,并按平均工资降序

    sql 复制代码
    SELECT department_name,location_id,COUNT(*),AVG(salary) avg_sal
    FROM departments d LEFT OUTER JOIN employees e
    ON d.department_id = e.department_id
    GROUP BY department_name,location_id#select中出现的非聚合函数的字段,必须出现在group by中
    ORDER BY avg_sal DESC;
  7. 查询每个部门的部门名,以及它对应工种的工种名和该工种的最低工资

    sql 复制代码
    SELECT department_name,job_id,MIN(salary)
    FROM departments d LEFT OUTER JOIN employees e
    ON d.department_id = e.department_id
    GROUP BY department_name,job_id;

该笔记根据尚硅谷的MySQL课程整理

相关推荐
异世界贤狼转生码农1 小时前
MongoDB Windows 系统实战手册:从配置到数据处理入门
数据库·mongodb
QuZhengRong1 小时前
【数据库】Navicat 导入 Excel 数据乱码问题的解决方法
android·数据库·excel
码农阿豪1 小时前
Windows从零到一安装KingbaseES数据库及使用ksql工具连接全指南
数据库·windows
冷崖6 小时前
MySQL异步连接池的学习(五)
学习·mysql
时序数据说7 小时前
时序数据库市场前景分析
大数据·数据库·物联网·开源·时序数据库
听雪楼主.10 小时前
Oracle Undo Tablespace 使用率暴涨案例分析
数据库·oracle·架构
我科绝伦(Huanhuan Zhou)10 小时前
KINGBASE集群日常维护管理命令总结
数据库·database
妖灵翎幺11 小时前
Java应届生求职八股(2)---Mysql篇
数据库·mysql
HMBBLOVEPDX11 小时前
MySQL的事务日志:
数据库·mysql
weixin_4196583113 小时前
MySQL数据库备份与恢复
数据库·mysql