1.3.4.10 SELECT的执行顺序
曾在1.3.4.5 日期运算 小节中,遇到别名出现在不同的字句中的情形,出现在 where 字句中,无法执行,直接报错。而出现在 order by 字句中,可以正常执行,这个和 SELECT 的执行顺序有关。
SELECT语句的完整语法:
(7) SELECT
(8) DISTINCT [select_list]
(1) FROM [left_table]
(3) [join_type] JOIN [right_table]
(2) ON [join_condition]
(4) WHERE [where_condition]
(5) GROUP BY [group_by_list]
(6) HAVING [having_condition]
(9) ORDER BY [order_by_condition]
(10) LIMIT [limit_number]
语法前面的序号为SELECT执行顺序;
MySQL的SELECT执行顺序一共分为10步,如上所标注的那样,最先执行的是FROM操作,最后执行的是LIMIT操作。其中每一次操作都会产生一张虚拟的表,这个虚拟的表作为一个处理的输入,只是这些虚拟的表对用户来说是透明的,但是只有最后一个虚拟的表才会被作为结果返回。如果没有在语句中指定某一个子句,那么将会跳过相应的步骤。
下面我们来具体分析一下查询处理的每一个阶段:
SELECT a.customer_id, COUNT(b.order_id) as total_orders
FROM table1 AS a
LEFT JOIN table2 AS b
ON a.customer_id = b.customer_id
WHERE a.city = 'hangzhou'
GROUP BY a.customer_id
HAVING count(b.order_id) < 2
ORDER BY total_orders DESC
LIMIT 0, 10;
- FORM: 对 FROM 左边的表和右边的表计算笛卡尔积,产生虚表 VT1。
- ON: 对虚表 VT1 进行 ON 过滤,只有那些符合 <join-condition> 的行才会被记录在虚表 VT2 中。
- JOIN: 如果指定了 OUTER JOIN(比如left join、 right join),那么保留表中未匹配的行就会作为外部行添加到虚拟表 VT2 中,产生虚拟表 VT3。
- WHERE: 对虚拟表 VT3 进行 WHERE 条件过滤。只有符合 <where-condition> 的记录才会被插入到虚拟表 VT4 中。
- GROUP BY: 根据 group by 子句中的列,对 VT4 中的记录进行分组操作,产生 VT5。
- HAVING: 对虚拟表 VT5 应用 having 过滤,只有符合 <having-condition> 的记录才会被 插入到虚拟表 VT6 中。
- SELECT: 执行 select 操作,选择指定的列,插入到虚拟表 VT7 中。
- DISTINCT: 对 VT7 中的记录进行去重。产生虚拟表 VT8.
- ORDER BY: 将虚拟表 VT8 中的记录按照 <order_by_list> 进行排序操作,产生虚拟表 VT9.
- LIMIT:取出指定行的记录,产生虚拟表 VT10, 并将结果返回。
了解到上面的内容,我们就可以很清楚的知道,为什么别名 monthBirth 出现在 where 字句中会报错,因为 monthBirth 出现在第 7 步中,而 where 在第 4 步中就执行了,所以错误消息提示:ERROR 1054 (42S22): Unknown column 'monthBirth' in 'where clause' ,而 order by 在 select 之后执行。