ORDER BY子句用于展示数据时对输出结果中的行进行排序。从逻辑查询处理来看,ORDER BY是最后处理的一个子句。下面的代码按照雇员ID和订单年份对输出结果进行排序:
2 FROM Sales.Orders
3 WHERE custid = 71
4 GROUP BY empid, YEAR (orderdate)
5 HAVING COUNT ( * ) > 1
6 ORDER BY empid,orderyear;
理解SQL最重要的一点就是要明白表不保证是有序的,因为表是为了代表一个集合(如果有重复项,则是多集),而集合是无序的。这意味着,如果在查询表时不指定一个ORDER BY子句,那么虽然查询可以返回一个结果表,但SQL Server可以自由地按任意顺序对结果中的行进行排序。为了确保结果中的行按照一定的顺序进行排序,唯一的方法就是显示地指定一个ORDER BY子句。不过,如果指定了ORDER BY子句,查询结果将不符合表的要求,因为这时结果中的行将具有一定的顺序。带有ORDER BY子句的查询会生成一种ANSI称之为游标(cursor)的结果(一种非关系结果,其中的行有固定的顺序)。你可能会问,查询返回表结果和返回游标,它们有什么区别?在SQL中的某些语言元素和运算预期只对查询的表结果进行处理,而不能处理游标,例如表表达式和集合运算。
注意,上例中的ORDER BY子句引用了别名列orderyear,这个别名是在SELECT处理阶段创建的。事实上,ORDER BY是唯一能够引用SELECT处理阶段创建的别名列的阶段,因为它是唯一一个在SELECT阶段之后被处理的阶段。
当要按照表达式的升序排序时,可以在表达式的后面指定ASC关键字(例如orderyear ASC),或者在表达式后面什么也不指定,因为ASC是默认值。如果想按照降序排序,则要在表达式后面指定DESC关键字(例如,orderyear DESC)。
SQL和T-SQL都支持在ORDER BY子句中指定表示该列名称或别名在SELECT列表中所处位置顺序的非负整数。例如,上述代码:
ORDER BY empid,orderyear
也可以写成:
ORDER BY 1,2
不过,从许多方面看,这时一种糟糕的编程习惯。首先,在关系模型中,属性(或列)本身没有顺序位置,要通过名称来引用它们。其次,当修改SELECT子句时,也可能忘记对ORDER BY子句中的引用位置做相应的修改。而如果使用列名称,代码就可以安全地避免这种错误。
T-SQL支持在ORDER BY子句中指定没有在SELECT子句中出现过的元素,也就是说,排序依据的列并不一定必须要在输出返回的列中选取。例如,以下查询按照雇佣日期对雇员进行排序,但最后并没有返回hiredate列:
2 FROM HR.Employees
3 ORDER BY hiredate;
但是,当指定了DISTINCT以后,ORDER BY子句就被限制为只能选取在SELECT列表中出现的那些元素。这一限制背后的原因是:当指定DISTINCT时,一个结果行可能代表多个原始行;因此,可能无法清楚地知道应该使用ORDER BY列表值中多个可能值中的哪一个。考虑以下无效的查询:
2 FROM HR.Employees
3 ORDER BY empid;
在Employees表中有9个雇员的信息(其中5位来自美国,4位来自英国)。如果不加上前面查询中那个无效的ORDER BY子句,结果将返回两行(每个不同的国家各一行)。因为每个国家在源表中的多行出现,每一个这样的行都有一个不同的雇员ID,这时ORDER BY empid实际上就无法定义了。