步骤2:Where阶段
对上一步返回的虚拟表中返回的所有行应用Where筛选器。只有让<where_predicate>逻辑条件为True的行,才会组成这一步要返回的虚拟表VT2。
注意:由于还有对表进行分组,所以在Where子句中不能使用聚合。
对于包含外联接的查询,有一个问题是让人困惑的,何时使用ON筛选器?何时Where筛选器?
两者的主要区别是:ON在添加外部行之前执行,而Where在添加外部行之后执行。ON中筛选掉的行不是最终的,因为步骤1-J3会将这些行再添加回来;相反Where筛选器对行的删除是最终的。
需要注意的是,只有在使用外联接时,ON和Where才有这种逻辑区别。当使用内连接时,它们是一致的。
步骤3:GROUP BY阶段
在Group By阶段,根据<group_by_specification>指定的列表,将上一步返回的虚拟表中的行分配到各个组,这一组列被称之为分组集。
例如:GROUP BY C.customerid中C.customerid就是一个分组集。
这个阶段将上一步返回的虚拟表中的行按组进行分组。由分组集中的所有属性值的每个唯一组合标识出一个组。最终得到的虚拟表VT3由两部分组成:分组后原来的行(原始信息),组标识符(组信息)。
组信息 C.customerid | 原始信息 C.customerid |
C.city |
O.orderid |
Jack | Jack Jack | ShangHai ShangHai | 1 2 |
Lucy | Lucy Lucy Lucy | Chongqing Chongqing Null | 3 4 5 |
Ajax | Ajax | Wuhan | 6 |
最终,Group By子句的查询将为每一个组生成一行。所以在查询中指定了Group By子句,则后面的所有步骤(Having,Select等)只能指定每个分组上的标量(单个)值表达式。这些表达式可以是Group By列表中的列,表达式(C.customerid),以及聚合行数(Count(C.customerid))。
这个阶段会认为两个NULL值是相等的。也就是说,所有的NULL值将被分配到同一个组中。
步骤4:HAVING阶段
HAVING筛选器用于对上一步返回的虚拟表中的组进行筛选。只有使<having_predicate>逻辑条件取值为True的组,才会称为这一步返回的虚拟表(VT4)的一部分。
注意:子查询不能作为聚合函数的输入。
以上内容来自《Microsoft SQL SERVER 2008技术内幕 T-SQL查询》