你不会以为SQL查询是从SELECT开始的吧?来来来,千万别打脸。
使用 group by 进行分组操作后,不能在 where 中使用聚合方法的别名。于是我又想到了另一个问题:SQL 查询的执行顺序是怎样的?很多 SQL 查询都是以 SELECT 开始的,自己已经写了很多 SQL 查询了,有一些还很复杂。但是我仍然很难确切地说出它的顺序是怎样的。
SQL 查询的执行顺序
于是我研究了一下,发现顺序大概是这样的。SELECT 并不是最先执行的,而是在第五个。
这张图回答了以下这些问题
这张图与 SQL 查询的语义有关,让你知道一个查询会返回什么,并回答了以下这些问题:
-
可以在 GRROUP BY 之后使用 WHERE 吗?(不行,WHERE 是在 GROUP BY 之前!) -
可以对窗口函数返回的结果进行过滤吗?(不行,窗口函数是 SELECT 语句里,而 SELECT 是在 WHERE 和 GROUP BY 之后) -
可以基于 GROUP BY 里的东西进行 ORDER BY 吗?(可以,ORDER BY 基本上是在最后执行的,所以可以基于任何东西进行 ORDER BY) -
LIMIT 是在什么时候执行?(在最后!)
在实际的数据库引擎中,并不一定严格按照这个顺序执行 SQL 查询,因为为了更快地执行查询,数据库引擎会做一些优化,这样就有可能改变子句的执行顺序,所以在涉及查询性能或者与索引有关的东西时,这张图就不适用了。
但是如果你想要知道一个查询语句是否合法,或者想要知道一个查询语句会返回什么,可以参考这张图。这个就是我们了解 SQL 子句执行顺序的意义。
我们就以下面的查询 SQL 为例,讲解一下整个 SQL 的执行顺序吧。
(6) SELECT [DISTINCT | ALL] COL1, AGE, GENDER
(1) FROM T1 JOIN T2
(2) ON T1.AID = T2.BID
(3) WHERE T1.AGE > 18 AND T2.GENDER = 'BOY'
(4) GROUP BY COL1
(5) HAVING AVG(AGE) >= 22
(7) UNION ALL
...
(8) ORDER BY COL1 DESC, COL2 ASC
(9) OFFSET 0 LIMIT 20
▼关注回复【面试】获取面试资料▼
步骤1:获取数据(From, Join)
首先,执行(1)From 和 Join 子句,对2张表进行组合,形成此次查询所需要的记录集合。
FROM T1 JOIN T2
步骤2:关联过滤(On)
From 和 Join 子句执行之后,处理器会根据 On 指定的条件从记录集合中挑出符合条件的记录:
ON T1.AID = T2.BID
步骤3:记录过滤(Where)
拿到了记录集合之后,开始执行 Where 子句。使用指定的条件过滤记录集合,如果计算结果不为 true,就会从记录集合中移除。
WHERE T1.AGE > 18 AND T2.GENDER = 'BOY'
步骤4:分组(Group by)
执行 Group by 子句,对记录集合分组,把 COL1 相同的放到一组。
GROUP BY COL1
步骤5:分组过滤(Having)
having中可以是普通条件的筛选,也能是聚合函数。而where只能是普通函数,一般情况下,有having可以不写where,把where的筛选放在having里,SQL语句看上去更丝滑。
HAVING AVG(AGE) >= 22
步骤6:筛选字段(Select)
select 子句是使用最多,也最容易理解的子句,从之前各个子句的结果集中,筛选出所需要的字段,同时可以做一些其它比如去重等操作。
SELECT [DISTINCT | ALL] COL1, AGE, GENDER
步骤7:合并(UNION ALL & UNION)
UNION ALL 对两个结果集进行并集操作,包括重复行,不进行排序;如果返回的两个结果集中有重复的数据,那么返回的结果集就会包含重复的数据了。如果想把结果集去重,可以使用 UNION。
步骤8:排序(ORDER BY)
ORDER BY 子句的操作就是对结果集排序,按字段先后进行排序,比如下列是COL1先做降序,如果相同的情况下按COL2进行升序排序。
ORDER BY COL1 DESC, COL2 ASC
步骤9:分页(OFFSET & LIMIT)
使用SELECT查询时,如果结果集数据量很大,比如几万行数据,放在一个页面显示的话数据量太大,不如分页显示,每次显示100条。
要实现分页功能,实际上就是从结果集中显示第1~100条记录作为第1页,显示第101~200条记录作为第2页,以此类推。
OFFSET 0 LIMIT 100