ToB企服应用市场:ToB评测及商务社交产业平台

标题: MySQL-08.聚合函数和SQL(DQL)的执行流程 [打印本页]

作者: 立山    时间: 2024-2-25 04:56
标题: MySQL-08.聚合函数和SQL(DQL)的执行流程
C-08 聚合(分组)函数和SQL(DQL)执行流程

上一章,讲到了SQL单行函数。实际上SQL函数还有一类,叫做聚合函数,或者多行,分组函数,它是对一组数据进行汇总的函数,输入的是一组数据的集合,输出的是单个值。
1.聚合函数的介绍

  1. /*
  2. SELECT [column,] group function(column),...
  3. FROM table_name
  4. [WHERE condition]
  5. GROUP BY column,
  6. [ORDER BY column];
  7. */
复制代码
1.1 AVG和SUM函数

只能对数值型的数据,使用AVG和SUM函数
  1. mysql> SELECT AVG(salary),SUM(salary),MAX(salary),MIN(salary)
  2.     -> FROM employees;
  3. +-------------+-------------+-------------+-------------+
  4. | AVG(salary) | SUM(salary) | MAX(salary) | MIN(salary) |
  5. +-------------+-------------+-------------+-------------+
  6. | 6461.682243 |   691400.00 |    24000.00 |     2100.00 |
  7. +-------------+-------------+-------------+-------------+
  8. 1 row in set (0.00 sec)
复制代码
1.2 MIN和MAX函数

可以对任意类型的数据使用MIN和MAX函数,但是常用于数值型和字符类型,以及日期时间类型。
  1. mysql> SELECT MIN(hire_date),MAX(hire_date)
  2.     -> FROM employees;
  3. +----------------+----------------+
  4. | MIN(hire_date) | MAX(hire_date) |
  5. +----------------+----------------+
  6. | 1987-06-17     | 2000-04-21     |
  7. +----------------+----------------+
  8. 1 row in set (0.00 sec)
复制代码
1.3 COUNT函数

  1. mysql> SELECT COUNT(*) FROM employees;# COUNT(1)的效果类似于COUNT(*),相当于把一行数据看作1去计数
  2. +----------+
  3. | COUNT(*) |
  4. +----------+
  5. |      107 |
  6. +----------+
  7. 1 row in set (0.00 sec
复制代码
  1. mysql> SELECT COUNT(commission_pct) FROM employees;
  2. +-----------------------+
  3. | COUNT(commission_pct) |
  4. +-----------------------+
  5. |                    35 |
  6. +-----------------------+
  7. 1 row in set (0.00 sec)
复制代码
2.GROUP BY

2.1 基本使用

可以使用GROUP BY子句将表中的数据分成若干组。
  1. /*
  2. SELECT [column,] group function(column),...
  3. FROM table_name
  4. [WHERE condition]
  5. [GROUP BY group_by_expression,]
  6. [ORDER BY column];
  7. */
复制代码
注意:

举例:
  1. SELECT department_id,AVG(salary)
  2. FROM employees
  3. GROUP BY department_id;
  4. SELECT AVG(salary)
  5. FROM employees
  6. GROUP BY department_id;
复制代码
2.2 使用多列分组
  1. SELECT department_id,job_id,SUM(salary)
  2. FROM employees
  3. GROUP BY department_id,job_id;
  4. -- GROUP BY job_id,department_id;结果一样
  5. -- 和排序子句不同,顺序不一样也不会对结果有影响
复制代码
2.3 GROUP BY中使用WITH ROLLUP

使用WITH ROLLUP关键字之后,在所有查询出的分组记录之后增加一条记录,该记录计算查询出所有记录的总和,即统计记录数量。
但是这个总和,和使用的分组函数有关。
  1. mysql> SELECT department_id,AVG(salary)
  2.     -> FROM employees
  3.     -> WHERE department_id > 80
  4.     -> GROUP BY department_id WITH ROLLUP;
  5. +---------------+--------------+
  6. | department_id | AVG(salary)  |
  7. +---------------+--------------+
  8. |            90 | 19333.333333 |
  9. |           100 |  8600.000000 |
  10. |           110 | 10150.000000 |
  11. |          NULL | 11809.090909 |
  12. +---------------+--------------+
  13. 4 rows in set (0.00 sec)
复制代码
3.HAVING

3.1 基本使用

过滤分组,HAVING子句
  1. /*
  2. SELECT [column,] group function(column),...
  3. FROM table_name
  4. [WHERE condition]
  5. [GROUP BY group_by_expression,]
  6. [HAVING group_condition,]
  7. [ORDER BY column];
  8. */
复制代码
  1. mysql> SELECT department_id,MAX(salary)
  2.     -> FROM employees
  3.     -> GROUP BY department_id
  4.     -> HAVING MAX(salary) > 10000;
  5. +---------------+-------------+
  6. | department_id | MAX(salary) |
  7. +---------------+-------------+
  8. |            20 |    13000.00 |
  9. |            30 |    11000.00 |
  10. |            80 |    14000.00 |
  11. |            90 |    24000.00 |
  12. |           100 |    12000.00 |
  13. |           110 |    12000.00 |
  14. +---------------+-------------+
  15. 6 rows in set (0.00 sec)
复制代码
  1. mysql> SELECT department_id,MAX(salary)
  2.     -> FROM employees
  3.     -> WHERE MAX(salary) > 10000
  4.     -> GROUP BY department_id;
  5. ERROR 1111 (HY000): Invalid use of group function
复制代码
3.2 WHERE和HAVING的对比

区别1:

​        WHER可以直接使用表中的字段作为筛选条件,但不能使用分组中的计算函数作为筛选条件,HAVING必须要与GROUP BY配合使用,可以把分组计算的函数和分组字段作为筛选条件。
区别2:

​        如果需要通过连接从关联表中获取需要的数据,WHERE是先筛选后连接,而HAVING是先连接后筛选。原因,再SQL的执行过程中会解释。

开发中的选择

WHERE和HAVING也不是互相互斥的,我们可以在一个查询里面同时使用WHERE和HAVING。包含分组统计函数的条件用HAVING,普通条件用WHERE,普通条件用WHERE。这样,才能发货WHERE的高效快速,又发挥HAVING可以使用包含分组统计函数的查询条件的优点。当数据量很大的时候,运行效率会有很大的区别。
4.SELECT的执行过程

4.1 查询的结构
  1. /*
  2. 方式1
  3. SELECT ...,...,...
  4. FROM ...,...,...
  5. WHERE 表的连接条件 AND 不包含分组函数的过滤条件
  6. GROUP BY 分组列名
  7. HAVING 包含分组函数的过滤条件
  8. ORDER BY ... ASC/DESC
  9. LIMIT ...,...;
  10. 方式2
  11. SELECT ...,...,...
  12. FROM ... (LEFT / RIGHT OUTER) | (INNER)JOIN ... ON 连接条件
  13. JOIN ... ON 连接条件
  14. WHERE 不包含分组函数的过滤条件
  15. GROUP BY 分组列名
  16. HAVING 包含分组函数的过滤条件
  17. ORDER BY ... ASC/DESC
  18. LIMIT ...,...;
  19. */
复制代码
4.2 SELECT 执行顺序
  1. /*
  2. 执行顺序,FROM 子句,从哪些表里查询 -> WHERE / ON 使用表的连接条件进行过滤数据 -> 使用WHERE中的非连接条件过滤数据 ->
  3. GROUP BY 对数据进行分组 -> HAVING 对分组后的数据进行过滤 -> SELECT 行过滤出显示的列 -> DISTINCT 有的话去重过滤 ->
  4. ORDER BY 对数据进行排序 -> LIMIT进行分页
  5. */
  6. -- 这里解释,为什么将不包含分组函数的条件写在WHERE会比HAVING中好,是因为,WHERE先执行,先过滤不满足的数据,可能会让数据量变小
  7. -- 后续的执行就处理的数据量小,效率自然就高了
  8. /*
  9. 关键字顺序
  10. SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT ...;
  11. */
复制代码
4.3 执行原理

SELECT 是先执行FROM这一子句,在这个阶段,如果是多张表联合查询,还会经历下面的步骤:
当然如果我们操作的是两张以上的表,就会重复上面1-3步骤,知道表多处理完毕,得到原始数据。
当拿到了查询数据表的原始数据,也就是最终的虚拟表vt1,就可以在此基础上进行WHERE阶段,对vt1表的结果进行筛选过滤,得到虚拟表vt2。
然后进行第三步和第四步,也就是GROUP BY和HAVING阶段。在这个阶段中,实际上是在虚拟表vt2的基础上进行分组和过滤,得到中甲你的虚拟表vt3和vt4。
当完成了条件筛选部分后,就可以筛选表中提取的字段,也就是进入到SELECT和DISTINCT阶段。
首先在SELECT阶段会提取到想要的字段,然后在DISTINCT阶段过滤掉重复的行,分别得到中间的虚拟表vt5-1和vt5-2。
当提取到想要展示的字段数据之后,就可以按照指定的字段进行排序,也就是ORDER BY阶段,得到虚拟表vt6。
最后在vt6的基础上,取出指定行的记录,也就是LIMIT阶段,得到最终的结果,对应的是虚拟表vt7。
当然SELECT语句,并不一定会写所有的关键字,未写的相应的字段就会省略。
同时因为SQL是一门结构化语言,所以在写SELECT语句时,要注意相应的关键字顺序,执行原理,就是执行的顺序。
只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4