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

但和SQL Server、Oracle最大的不同是对SELECT列表的处理。在MS SQL和Oracle中,select_list是在group by和having子句之后才进行的,这意味着group by分组后,不能在select_list中指定非分组列(除非聚合运算),反过来看,在group by中不能使用select_list中的别名列。

但在MariaDB和MySQL中,select_list是在group by之前进行的。在group by中能够引用select_list中的列,在select_list中也能指定非分组列。

mariadb和mysql在这一点上实际上是"不规范"的,因为它违背了数据库的设计范式。详细内容在后文分析。

1.2.3 MySQL的逻辑执行顺序

如下图:

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

和MariaDB之间并没有什么区别,仅仅只是MySQL不支持开窗函数over()。

但是注意,从mysql 5.7.5开始,已经默认设置了sql_mode=ONLY_FULL_GROUP_BY,这意味着MySQL默认也将遵循SQL规范,对于那些非分组列又没有进行聚合的列,都不允许出现在select_list中,除非select_list中使用的列是主键或者唯一索引列,之所以允许这样的行为,是因为有功能依赖性决定了它可以这样做,由此保证"规范性"。同样的,为何不规范的问题见后文。

1.3 关于表表达式和虚拟表

派生表、CTE(公用表表达式,有的数据库系统支持)、视图和表函数都是表,我们常称之为"表表达式",只不过它们是虚拟表(这里的虚拟表和上面逻辑执行过程中产生的虚拟表vt不是同一个概念)。它们都必须满足成为表的条件,这也是为什么定义表表达式的时候有些语法不能使用。

从关系模型上去分析。表对应的是关系模型中的关系,表中的列对应的是关系模型中的元素。

一方面,关系和元素都需要有唯一标识的名称,因此表和列也要有名称,即使表表达式也如此。像派生表是嵌套在语句中的,无法在外部给它指定表明,因此必须为它指定一个表别名。同理,表表达式中的别名也一样,必须唯一且必须要有。

另一方面,关系中的元素是无序的,因此表和表表达式中的数据也应当是无序的。虽然有些表表达式中可以使用ORDER BY子句,但这时候的ORDER BY只是为了让TOP/LIMIT子句来挑选指定数量的行,并不是真的会对结果排序。也就是说表表达式挑选出来的行就像表一样,其内数据行仍然是无序的,以后访问它们的时候是按照物理存储顺序进行访问的,即使表表达式的定义语句中使用了ORDER BY子句。

关于数据的无序性和随机性,见下文。

这里还请区分表表达式(虚拟表)和逻辑执行过程中我们想象出来的虚拟表。表表达式是实实在在符合关系模型的表,即使它可能只是一条或几条语句,也不会将相关数据行进行物理的存储,但在关系引擎看来,它就是表。而逻辑执行过程中我们想象出来的虚拟表,只是为了方便理解而描述出来的,实际上不会有这样的表,它们只是按一定规则存放在内存中的一些数据行,虽然某些步骤中可能也会使用系统自建的临时表存放中途的数据,但它们不是表。

1.4 关于表别名和列别名

在SQL语句中,我们避免不了要对表、列使用别名进行引用。关于别名,需要注意两点:

(1).定义了表别名后,在语句中对该表的引用都必须使用别名,而不能使用原表名。

(2).引用别名时,注意查询的逻辑处理过程。在某一阶段只能引用该阶段前面阶段定义的别名,使用该阶段后才定义的别名将报错。

例如下面的两个查询语句,第一个错误原因是不能引用原表名,第二个错误是因为WHERE阶段不能引用SELECT阶段定义的字段别名。

SELECT Student.Name FROM Student AS 学生表
SELECT Name,Sex AS 性别 FROM Student WHERE 性别 = '男'

下面是正确的写法。

SELECT 学生表.Name FROM Student AS 学生表
SELECT Name,Sex AS性别 FROM Student WHERE Sex = '男' 

1.5 关于数据无序性和ORDER BY

在关系型数据库中,必须时刻都铭记在心的是"集合元素是无序"的,体现在数据库中就是"表中数据行是无序的",除非建立了相关索引。

出于集合模型的考虑,像我们平时看到的有行、有列的二维表数据(下图左边),更应该看作是下图右边的结合结构,因为集合是无序的。

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

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

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