SQL语句逻辑执行过程和相关语法详解(6)

MariaDB [test]> select * from Student;
+------+----------+------+--------+
| sid  | name    | age  | class  |
+------+----------+------+--------+
|    1 | chenyi  |  22 | Java  |
|    2 | huanger  |  23 | Python |
|    3 | zhangsan |  21 | Java  |
|    4 | lisi    |  20 | C#    |
|    5 | wangwu  |  21 | Python |
|    6 | zhaoliu  |  19 | Java  |
|    7 | qianqi  |  22 | C      |
|    8 | sunba    |  20 | C++    |
|    9 | yangjiu  |  24 | Java  |
+------+----------+------+--------+

现在按照class进行分组。下面是分组后经过我加工的表结构:

SQL语句逻辑执行过程和相关语法详解

其中第一列是分组得到的结果,我把它和原表的数据结合在一起了。注意,这是一个不符合关系模型范式要求的结构。

在分组前,关系引擎会对sid、name、age和class列的每一行进行筛选。但是分组后,关系引擎只看得到第一列,也就是class列,而sid、name和age列被直接忽略,因此无法引用它们。

关于GROUP BY,有以下两个问题:

1.为什么分组之后涉及到对组的操作时只允许返回标量值?

标量值即单个值,比如聚合函数返回的值就是标量值。在分组之后,组将成为表的工作中心,一个组将成为一个整体,所有涉及到分组的查询,将以组作为操作对象。组的整体是重要的,组中的个体不重要,甚至可以理解为分组后只有组的整体,即上图中左边加粗的部分,而组中的个体是透明的。

以上图中的第一条记录举一个通俗的例子。在分组以前,知道了该学生的姓名"chenyi"之后,关注点可能要转化为它的主键列sid值"1",因为主键列唯一标识每一行,知道了主键值就知道了该行的所有信息。而在分组之后,关注的中心只有分组列class,无论是知道姓名"chenyi"还是学号"1"都不是关注的重点,重点是该行记录(集合的元素)是属于"Java"班级的

这就能解释为什么只能以组作为操作对象并返回标量值。例如,在分组之后进行SUM汇总,将以"Java"班作为一个汇总对象,以"Python"班作为另一个汇总对象,汇总的将是每个分组的总值,而不是整个表的总值,并且汇总的值是一个标量值,不会为组中的每行都返回这个汇总值。否则就违反了关系模型的范式。

2.为什么分组之后只能使用GROUP BY列表中的列,如果不在GROUP BY列表中,就必须进行聚合?

分组后分组列成为表的工作中心,以后的操作都必须只能为组这个整体返回一个标量值。

如果使用了非分组列表的列,将不能保证这个标量值。例如,分组后对"Java"班返回了一个汇总值,假如同时要使用sid列和name列,因为这两列没有被聚合或分组,因此只能为这两列的每个值返回一行,也就是说在返回汇总标量值的同时还要求返回"Java"班组中的每一行,要实现这样的结果,需要整合为如上图所示的结果,但在关系表中这是违反规范的。正如前文介绍的DISTINCT一样,ORDER BY的排序列只能使用DISTINCT去重的select_list列表。

因此,分组后只能使用分组列表中的列。如果要使用非分组列表中的列,应该让它们也返回一个标量值,只有这样才能实现分组列和非分组列结果的整合。例如,下面的语句将会产生错误,因为select_list在GROUP BY阶段后执行,且select_list中的列没有包含在GROUP BY中,也没有使用聚合函数。

SELECT sid,name FROM Student GROUP BY class;

事实上从严格意义上看待这条语句,它没有实现分组的意义:既然不返回分组列的分组结果,那为什么还要进行分组呢?

其实,无论是标准SQL还是MySQL、mariadb,执行group by子句时都会表扫描并创建一个临时表(此处为了说明group by的特性,不考虑group by使用索引优化的情况),这个临时表中只有group by的分组列,没有那些非分组列。这也是前面说group by之后,关系引擎的目光从行转为组的真正原因。由此,已经足够说明为什么select_list中不能使用非group by的分组列。

1.10 关于MySQL/MariaDB的GROUP BY

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/90c3b57f9b6508b170ad70d479052a49.html