首先作者给出了如下的sql查询语句执行顺序
() select () distinct () <top_specification> <select_list>
()from <left_table>
() <join_type> join <right_table>
() on <join _condition>
() where <where_condition>
()group by <group_by_list>
() with {cube|rollup}
()having(having_condition)
() order by <order_by_condition>
从这个顺序中我们不难发现所有的 查询语句都是从from开始执行的在执行过程中每个步骤都会为
下一个步骤生成一个虚拟表这个虚拟表将作为下一个执行步骤的输入
第一步首先对from子句中的前两个表执行一个笛卡尔乘积此时生成虚拟表 vt
第二步接下来便是应用on筛选器on 中的逻辑表达式将应用到 vt 中的各个行筛选出满足on逻辑表达式的行生成虚拟表 vt
第三步如果是outer join 那么这一步就将添加外部行left outer jion 就把左表在第二步中过滤的添加进来如果是right outer join 那么就将右表在第二步中过滤掉的行添加进来这样生成虚拟表 vt
第四步如果 from 子句中的表数目多余两个表那么就将vt和第三个表连接从而计算笛卡尔乘积生成虚拟表该过程就是一个重复的步骤最终得到一个新的虚拟表 vt
第五步应用where筛选器对上一步生产的虚拟表引用where筛选器生成虚拟表vt在这有个比较重要的细节不得不说一下对于包含outer join子句的查询就有一个让人感到困惑的问题到底在on筛选器还是用where筛选器指定逻辑表达式呢?on和where的最大区别在于如果在on应用逻辑表达式那么在第三步outer join中还可以把移除的行再次添加回来而where的移除的最终的
举个简单的例子有一个学生表(班级姓名)和一个成绩表(姓名成绩)我现在需要返回一个x班级的全体同学的成绩但是这个班级有几个学生缺考也就是说在成绩表中没有记录为了得到我们预期的结果我们就需要在on子句指定学生和成绩表的关系(学生姓名=成绩姓名)那么我们是否发现在执行第二步的时候对于没有参加考试的学生记录就不会出现在vt中因为他们被on的逻辑表达式过滤掉了但是我们用left outer join就可以把左表(学生)中没有参加考试的学生找回来因为我们想返回的是x班级的所有学生如果在on中应用学生班级=x的话那么在left outer join 中就会将不会把x班级的学生的所有记录找回来所以只能在where筛选器中应用 学生班级=x 应为它的过滤是最终的
第六步group by 子句将中的唯一的值组合成为一组得到虚拟表vt如果应用了group by那么后面的所有步骤都只能得到的vt的列或者是聚合函数(countsumavg等)原因在于最终的结果集中只为每个组包含一行这一点请牢记
第七步应用cube或者rollup选项为vt生成超组生成vt
第八步应用having筛选器生成vthaving筛选器是第一个也是为唯一一个应用到已分组数据的筛选器
第九步处理select列表将vt中的在select中出现的列筛选出来生成vt
第十步应用distinct子句vt中移除相同的行生成vt事实上如果应用了group by子句那么distinct是多余的原因同样在于分组的时候是将列中唯一的值分成一组同时只为每一组返回一行记录那么所以的记录都将是不相同的
第十一步应用order by子句按照order_by_condition排序vt此时返回的一个游标而不是虚拟表sql是基于集合的理论的集合不会预先对他的行排序它只是成员的逻辑集合成员的顺序是无关紧要的对表进行排序的查询可以返回一个对象这个对象包含特定的物理顺序的逻辑组织这个对象就叫游标正因为返回值是游标那么使用order by 子句查询不能应用于表表达式排序是很需要成本的除非你必须要排序否则最好不要指定order by最后在这一步中是第一个也是唯一一个可以使用select列表中别名的步骤
第十二步应用top选项此时才返回结果给请求者即用户到此为止我们将一个sql查询语句的逻辑执行过程梳理了一遍对于使用查询语句多年的我来说无疑对以前的不少问题得出了解答希望你也能从中受益我将在后面介绍sqlserver 中新加入的逻辑处理阶段