OVER子句用于为行为定义一个窗口(windows),以便进行特定的运算。可以把行的窗口简单地认为是运算将要操作的一个行的集合。例如,聚合函数和排名函数都是可以支持OVER子句的运算类型。由于OVER子句为这些函数提供了一个行的窗口,所以这些函数也称之为开窗函数。
聚合函数的要点就是要对一组值进行聚合,聚合函数传统上一直以GROUP BY查询作为操作的上下文。在前面的“GROUP BY”子句的讨论中,我们知道在对数据进行分组以后,查询为每个组只返回一行;因此,也就是要限制所有的表达式为每个组只能返回一个值。
聚合开窗函数使用OVER子句提供窗口作为上下文,对窗口中的一组值进行操作,而不是使用GROUP BY子句提供的上下文。这样就不必对数据进行分组,还能够在同一行中同时返回基础行的列和聚合列。为了理解OVER子句,现在考虑Sales.OrderValues视图,现在只要简单地把视图看作是一个表就可以了。Sales.OrderValues视图的每一行代表一个订单,包含订单ID(orderid),客户ID(custid)、雇员ID(empid)、承运人ID(shipperid)、订单日期(orderdate),以及订单价格(val)。
带有空括号的OVER子句会提供所有行进行计算。这里的“所有行”并不一定是在FROM子句中出现的那些表中的所有行,而是在FROM、WHERE、GROUP BY,以及HAVING处理阶段完成后仍然可用的那些行。注意,只有在SELECT和ORDER BY处理阶段才允许使用OVER子句。这里只中点介绍在SELECT处理阶段如何使用OVER子句。例如,如果在对OrderValues视图进行查询的SELECT子句中指定了SUM(val) OVER()表达式,这个函数就会对SELECT阶段操作的所有行计算其总价格。
如果查询在SELECT阶段之前没有过滤数据,也没有应用其他的逻辑阶段,这个表达式将返回OrderValues视图中所有行的总价格。如果想对行进行限制或分区,则可以使用PARTITION BY子句。例如,现在不想返回OrderValues中所有行的总价格,而只是想返回当前客户(和当前行具有相同custid的所有行)的总价格,则可以指定SUM(val) OVER(PARTITION BY custid)。
以下查询可以返回OrderValues的所有行,并且演示了同时使用非分区和分区表达式的方法。此外,每一行除了基本列以外,查询还会返回所有行的总价格和当前客户的总价格:
@H_403_15@ 1 SELECT orderid,custid,val, 2 SUM (val) OVER () AS totalvalue, 3 SUM (val) OVER (PARTITION BY custid) AS custtotalvalue 4 FROM Sales.OrderValues;
这个查询返回以下结果:
所有结果行的totalvalue列表示所有行的价格总数。custtotalvalue列表示所有行中与当前行具有相同custid值的那些行的价格总数。
OVER子句的一个优点就是能够在返回基本列的同时,在同一行对它们进行聚合;也可以在表达式中混合使用基本列和聚合值列。例如,以下查询为OrderValues的每一行计算当前价格占总价格的百分比,以及当前价格占客户总价格的百分比。
@H_403_15@ 1 SELECT orderid, 2 ROW_NUMBER() OVER ( ORDER BY val) AS rownum, 3 RANK() OVER ( ORDER BY val) AS rank, 4 DENSE_RANK() OVER ( ORDER BY val) AS dense_rank, 5 NTILE( 10 ) OVER ( ORDER BY val) AS ntile 6 FROM Sales.OrderValues 7 ORDER BY val;