TOP选项

  TOP选项是T-SQL特有的,用于限制查询返回的行数或百分比。当在查询中指定了ORDER BY子句时,TOP将依赖该子句来定义行和逻辑优先顺序。例如,如果要从Orders表返回最近的5个订单,则可以在SELECT子句中指定TOP(5),并在ORDER BY子句中指定orderdate DESC,如以下代码:

1 SELECTTOP(5) orderid,orderdate,custid,empid
2 FROM Sales.Orders
3 ORDERBY orderdate DESC;

  从逻辑查询处理的角度来看,TOP选项是作为SELECT阶段的一部分而处理的,紧接着DISTINCT子句处理之后(如果存在DISTINCT)。注意,当在查询中指定了TOP以后,ORDER BY子句就会起到双重作用。首先,作为SELECT处理阶段一部分的TOP选项要依靠ORDER BY子句先为各个行定义它们的逻辑优先顺序,在这种优秀顺序的基础上再去过滤其他请求。其次,作为SELECT处理阶段之后的ORDER BY阶段,与为了展示数据而对行进行排序的ORDER BY子句完全一样。例如,上述代码的查询返回orderdate值最大的前5行,并按照orderdate DESC对输出结果中的行进行排序。

  当使用TOP时,同一ORDER BY子句既担当了为TOP决定行的逻辑优先顺序的角色,同时也担当了它的常规角色(展示数据),只是最终生成的结果由表变成了具有固定顺序的游标。例如,不能在同一查询中既通过一个ORDER BY列表来为TOP选项决定各行的逻辑优先顺序,同时还想用另一个ORDER BY对输出中的行进行排序以展示数据,根本不能这样用。为了实现这个查询,就得使用所谓的表表达式(table expression)。

  在TOP选项中可以使用PERCENT关键字,在这种情况下,SQL Server会按照百分比来计算应该返回的满足条件的行数(向上取整)。例如,以下查询返回最近更新过的前1%个订单:

1 SELECTTOP(1) PERCENT orderid,orderdate,custid,empid
2 FROM Sales.Orders
3 ORDERBY orderdate DESC;

  查询返回9行,因为Orders表有830行,830的1%,再向上取整数,就是9。

  在上述代码的查询中,ORDER BY列的orderdate取值不是唯一的,因为在orderdate列上并没有定义主键或唯一性约束。多个行可能具有相同的订单日期。在没有指定附加属性(tiebreaker)的情况下,行(具有相同订单日期的行)之间的优先关系是没有定义的。这一事实让查询具有一定的不确定性,多个查询结果都可以认为是正确的。这时,SQL Server只是根据物理上最先访问到了哪行,就选择相应的行。

  在上述代码的查询中,还应该注意到,返回行中最小的订单日期是2008年5月4日,输出中具有这个日期的只有1行。表中的其他行可能具有相同的订单日期,在已有的ORDER BY列表中不能确定行的唯一顺序的情况下,并不能保证最终将返回这些行中的哪一行。

  如果想让查询是确定性的,就要让ORDER BY列表能唯一地决定一行;换句话说,要为ORDER BY列表增加一个附加属性。例如,可以在ORDER BY列表中增加一列orderid DESC,如下代码所示;这样,当需要最终决定各行的优先顺序时,可以按照订单ID的降序来排序。

1 SELECTTOP(5) orderid,orderdate,custid,empid
2 FROM Sales.Orders
3 ORDERBY orderdate DESC,orderid DESC;

  除了在ORDER BY列表中增加附加属性,还可以请求返回所有具有相同结果的行。例如,除了返回上述查询中的5行,还能够请求返回与TOP n行中最后一行(在这个例子中是2008年5月4日)的排序值(在这个例子中是订单日期orderdate值)相同的其他行。为此,须增加一个WITH TIES选项,如下所示:

1 SELECTTOP(5) WITH TIES orderid,orderdate,custid,empid
2 FROM Sales.Orders
3 ORDERBY orderdate DESC;

  注意,上述代码中即便指定了TOP(5),输出还是包含了8行。SQL Server先按照orderdate DESC的顺序,返回TOP(5)行;再从表中返回orderdate值和已经访问过的前5行中最后一行相同的其他所有行。

posted @ 2012-09-24 10:19  沙耶  阅读(522)  评论(0编辑  收藏  举报