关于sql和MySQL的语句执⾏顺序(必看)
ql和mysql执⾏顺序,发现内部机制是⼀样的。最⼤区别是在别名的引⽤上。
⼀、sql执⾏顺序
(1)from
(3) join
(2) on
(4) where
(5)group by(开始使⽤select中的别名,后⾯的语句中都可以使⽤)
(6)
(7)having
(8) select
(9) distinct
(10) order by
从这个顺序中我们不难发现,所有的查询语句都是从from开始执⾏的,在执⾏过程中,每个步骤都会为下⼀个步骤⽣成⼀个虚拟表,这个虚拟表将作为下⼀个执⾏步骤的输⼊。
第⼀步:⾸先对from⼦句中的前两个表执⾏⼀个笛卡尔乘积,此时⽣成虚拟表 vt1(选择相对⼩的表做基础表)
第⼆步:接下来便是应⽤on筛选器,on 中的逻辑表达式将应⽤到 vt1 中的各个⾏,筛选出满⾜on逻辑表达式的⾏,⽣成虚拟表 vt2
第三步:如果是outer join 那么这⼀步就将添加外部⾏,left outer jion 就把左表在第⼆步中过滤的添加进来,如果是right outer join 那么就将右表在第⼆步中过滤掉的⾏添加进来,这样⽣成虚拟表 vt3
第四步:如果 from ⼦句中的表数⽬多余两个表,那么就将vt3和第三个表连接从⽽计算笛卡尔乘积,⽣成虚拟表,该过程就是⼀个重复1-3的步骤,最终得到⼀个新的虚拟表 vt3。
第五步:应⽤where筛选器,对上⼀步⽣产的虚拟表引⽤where筛选器,⽣成虚拟表vt4,在这有个⽐较
重要的细节不得不说⼀下,对于包含outer join ⼦句的查询,就有⼀个让⼈感到困惑的问题,到底在on筛选器还是⽤where筛选器指定逻辑表达式呢?on和where的最⼤区别在于,如果在on应⽤逻辑表达式那么在第三步outer join中还可以把移除的⾏再次添加回来,⽽where的移除的最终的。举个简单的例⼦,有⼀个学⽣表(班级,姓名)和⼀个成绩表(姓名,成绩),我现在需要返回⼀个x班级的全体同学的成绩,但是这个班级有⼏个学⽣缺考,也就是说在成绩表中没有记录。为了得到我们预期的结果我们就需要在on⼦句指定学⽣和成绩表的关系(学⽣.姓名=成绩.姓名)那么我们是否发现在执⾏第⼆步的时候,对于没有参加考试的学⽣记录就不会出现在vt2中,因为他们被on的逻辑表达式过滤掉了,但是我们⽤left outer join就可以把左表(学⽣)中没有参加考试的学⽣回来,因为我们想返回的是x班级的所有学⽣,如果在on中应⽤学⽣.班级='x'的话,left outer join会把x班级的所有学⽣记录回(感谢⽹友康钦谋__康钦苗的指正),所以只能在where筛选器中应⽤学⽣.班级='x' 因为它的过滤是最终的。
第六步:group by ⼦句将中的唯⼀的值组合成为⼀组,得到虚拟表vt5。如果应⽤了group by,那么后⾯的所有步骤都只能得到的vt5的列或者是聚合函数(count、sum、avg等)。原因在于最终的结果集中只为每个组包含⼀⾏。这⼀点请牢记。
第七步:应⽤cube或者rollup选项,为vt5⽣成超组,⽣成vt6.
第⼋步:应⽤having筛选器,⽣成vt7。having筛选器是第⼀个也是为唯⼀⼀个应⽤到已分组数据的筛选器。
第九步:处理select⼦句。将vt7中的在select中出现的列筛选出来。⽣成vt8.
第⼗步:应⽤distinct⼦句,vt8中移除相同的⾏,⽣成vt9。事实上如果应⽤了group by⼦句那么distinct是多余的,原因同样在于,分组的时候是将列中唯⼀的值分成⼀组,同时只为每⼀组返回⼀⾏记录,那么所以的记录都将是不相同的。
第⼗⼀步:应⽤order by⼦句。按照order_by_condition排序vt9,此时返回的⼀个游标,⽽不是虚拟表。sql是基于集合的理论的,集合不会预先对他的⾏排序,它只是成员的逻辑集合,成员的顺序是⽆关紧要的。对表进⾏排序的查询可以返回⼀个对象,这个对象包含特定的物理顺序的逻辑组织。这个对象就叫游标。正因为返回值是游标,那么使⽤order by ⼦句查询不能应⽤于表表达式。排序是很需要成本的,除⾮你必须要排序,否则最好不要指定order by,最后,在这⼀步中是第⼀个也是唯⼀⼀个可以使⽤select列表中别名的步骤。
第⼗⼆步:应⽤top选项。此时才返回结果给请求者即⽤户。
⼆、mysql的执⾏顺序
SELECT语句定义
⼀个完成的SELECT语句包含可选的⼏个⼦句。SELECT语句的定义如下:
SQL代码
[java]
1. <SELECT clause> [<FROM clause>] [<WHERE clause>] [<GROUP BY clause>] [<HAVING clause>] [<ORDER BY clause>] [<LIMIT clause>]  SELECT⼦句是必选的,其它⼦句如WHERE⼦句、GROUP BY⼦句等是可选的。
⼀个SELECT语句中,⼦句的顺序是固定的。例如GROUP BY⼦句不会位于WHERE⼦句的前⾯。
SELECT语句执⾏顺序
SELECT语句中⼦句的执⾏顺序与SELECT语句中⼦句的输⼊顺序是不⼀样的,所以并不是从SELECT⼦句开始执⾏的,⽽是按照下⾯的顺序执⾏:开始->FROM⼦句->WHERE⼦句->GROUP BY⼦句->HAVING⼦句->ORDER BY⼦句->SELECT⼦句->LIMIT⼦句->最终结果
每个⼦句执⾏后都会产⽣⼀个中间结果,供接下来的⼦句使⽤,如果不存在某个⼦句,就跳过
对⽐了⼀下,mysql和sql执⾏顺序基本是⼀样的, 标准顺序的 SQL 语句为:
[html]
1. select 考⽣姓名, max(总成绩) as max总成绩
2.
3. from tb_Grade
4.
5. where 考⽣姓名 is not null
6.
7. group by 考⽣姓名mysql group by order by
8.
9. having max(总成绩) > 600
10.
11. order by max总成绩
在上⾯的⽰例中 SQL 语句的执⾏顺序如下:
  (1). ⾸先执⾏ FROM ⼦句, 从 tb_Grade 表组装数据源的数据
  (2). 执⾏ WHERE ⼦句, 筛选 tb_Grade 表中所有数据不为 NULL 的数据
  (3). 执⾏ GROUP BY ⼦句, 把 tb_Grade 表按 "学⽣姓名" 列进⾏分组(注:这⼀步开始才可以使⽤select中的别名,他返回的是⼀个游标,⽽不是⼀个表,所以在where中不可以使⽤select中的别名,⽽having却可以使⽤,感谢⽹友  zyt1369  提出这个问题)
  (4). 计算 max() 聚集函数, 按 "总成绩" 求出总成绩中最⼤的⼀些数值
  (5). 执⾏ HAVING ⼦句, 筛选课程的总成绩⼤于 600 分的.
  (7). 执⾏ ORDER BY ⼦句, 把最后的结果按 "Max 成绩" 进⾏排序.