VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 数据库 > SQL教程 >
  • SQL 对查询结果进行排序(ORDER BY)

学习重点

  • 使用 ORDER BY 子句对查询结果进行排序。

  • 在 ORDER BY 子句中列名的后面使用关键字 ASC 可以进行升序排序,使用 DESC 关键字可以进行降序排序。

  • ORDER BY 子句中可以指定多个排序键。

  • 排序健中包含 NULL 时,会在开头或末尾进行汇总。

  • ORDER BY 子句中可以使用 SELECT 子句中定义的列的别名。

  • ORDER BY 子句中可以使用 SELECT 子句中未出现的列或者聚合函数。

  • ORDER BY 子句中不能使用列的编号。

一、ORDER BY 子句

截至目前,我们使用了各种各样的条件对表中的数据进行查询。本节让我们再来回顾一下简单的 SELECT 语句(代码清单 27)。

代码清单 27 显示商品编号、商品名称、销售单价和进货单价的 SELECT 语句


 
SELECT product_id, product_name, sale_price, purchase_price
 
FROM Product;

执行结果


 
product_id | product_name | sale_price | purchase_price
 
------------+---------------+--------------+----------------
 
0001 | T恤衫 | 1000 | 500
 
0002 | 打孔器 | 500 | 320
 
0003 | 运动T恤 | 4000 | 2800
 
0004 | 菜刀 | 3000 | 2800
 
0005 | 高压锅 | 6800 | 5000
 
0006 | 叉子 | 500 |
 
0007 | 擦菜板 | 880 | 790
 
0008 | 圆珠笔 | 100 |
 
 

对于上述结果,在此无需特别说明,本节要为大家介绍的不是查询结果,而是查询结果的排列顺序。

那么,结果中的 8 行记录到底是按照什么顺序排列的呢?乍一看,貌似是按照商品编号从小到大的顺序(升序)排列的。其实,排列顺序是随机的,这只是个偶然。因此,再次执行同一条 SELECT 语句时,顺序可能大为不同。

KEYWORD

  • 升序

通常,从表中抽取数据时,如果没有特别指定顺序,最终排列顺序便无从得知。即使是同一条 SELECT 语句,每次执行时排列顺序很可能发生改变。

但是不进行排序,很可能出现结果混乱的情况。这时,便需要通过在 SELECT 语句末尾添加 ORDER BY 子句来明确指定排列顺序。

KEYWORD

  • ORDER BY 子句

ORDER BY 子句的语法如下所示。

语法 4 ORDER BY 子句


 
SELECT <列名1>, <列名2>, <列名3>, ……
 
FROM <表名>
 
ORDER BY <排序基准列1>, <排序基准列2>, ……

例如,按照销售单价由低到高,也就是升序排列时,请参见代码清单 28。

代码清单 28 按照销售单价由低到高(升序)进行排列


 
SELECT product_id, product_name, sale_price, purchase_price
 
FROM Product
 
ORDER BY sale_price;

执行结果

按照销售单价由低到高(升序)进行排列

不论何种情况,ORDER BY 子句都需要写在 SELECT 语句的末尾。这是因为对数据行进行排序的操作必须在结果即将返回时执行。ORDER BY 子句中书写的列名称为排序键。该子句与其他子句的顺序关系如下所示。

KEYWORD

  • 排序键

▶ 子句的书写顺序

  1. SELECT 子句 → 2. FROM 子句 → 3. WHERE 子句 → 4. GROUP BY 子句 → 5. HAVING 子句 → 6. ORDER BY 子句

法则 15

ORDER BY 子句通常写在 SELECT 语句的末尾。

不想指定数据行的排列顺序时,SELECT 语句中不写 ORDER BY 子句也没关系。

二、指定升序或降序

与上述示例相反,想要按照销售单价由高到低,也就是降序排列时,可以参见代码清单 29,在列名后面使用 DESC 关键字

KEYWORD

  • 降序

  • DESC 关键字

代码清单 29 按照销售单价由高到低(降序)进行排列


 
SELECT product_id, product_name, sale_price, purchase_price
 
FROM Product
 
ORDER BY sale_price DESC;

执行结果


 
product_id | product_name | sale_ price | purchase_ price
 
------------+--------------+-------------+----------------
 
0005 | 高压锅 | 6800 | 5000
 
0003 | 运动T恤 | 4000 | 2800
 
0004 | 菜刀 | 3000 | 2800
 
0001 | T恤衫 | 1000 | 500
 
0007 | 擦菜板 | 880 | 790
 
0002 | 打孔器 | 500 | 320
 
0006 | 叉子 | 500 |
 
0008 | 圆珠笔 | 100 |
 
 

如上所示,这次销售单价最高(6800 日元)的高压锅排在了第一位。其实,使用升序进行排列时,正式的书写方式应该是使用关键字 ASC,但是省略该关键字时会默认使用升序进行排序。这可能是因为实际应用中按照升序排序的情况更多吧。ASC 和 DESC 是 ascendent(上升的)和 descendent(下降的)这两个单词的缩写。

KEYWORD

  • ASC 关键字

法则 16

未指定 ORDER BY 子句中排列顺序时会默认使用升序进行排列。

由于 ASC 和 DESC 这两个关键字是以列为单位指定的,因此可以同时指定一个列为升序,指定其他列为降序。

三、指定多个排序键

本节开头曾提到过对销售单价进行升序排列的 SELECT 语句(代码清单 28)的执行结果,我们再来回顾一下。可以发现销售单价为 500 日元的商品有 2 件。相同价格的商品的顺序并没有特别指定,或者可以说是随机排列的。

如果想要对该顺序的商品进行更细致的排序的话,就需要再添加一个排序键。在此,我们以添加商品编号的升序为例,请参见代码清单 30。

代码清单 30 按照销售单价和商品编号的升序进行排序


 
SELECT product_id, product_name, sale_price, purchase_price
 
FROM Product
 
ORDER BY sale_price, product_id;

执行结果

按照销售单价和商品编号的升序进行排序

这样一来,就可以在 ORDER BY 子句中同时指定多个排序键了。规则是优先使用左侧的键,如果该列存在相同值的话,再接着参考右侧的键。当然,也可以同时使用 3 个以上的排序键。

四、NULL 的顺序

在此前的示例中,我们已经使用过销售单价(sale_price 列)作为排序键了,这次让我们尝试使用进货单价(purchase_price 列)作为排序键吧。此时,问题来了,圆珠笔和叉子对应的值是 NULL,究竟 NULL 会按照什么顺序进行排列呢? NULL 是大于 100 还是小于 100 呢?或者说 5000 和 NULL 哪个更大呢?

请大家回忆一下我们在 算术运算符和比较运算符 中学过的内容。没错,不能对 NULL 使用比较运算符,也就是说,不能对 NULL 和数字进行排序,也不能与字符串和日期比较大小。因此,使用含有 NULL 的列作为排序键时, NULL 会在结果的开头或末尾汇总显示(代码清单 31)。

代码清单 31 按照进货单价的升序进行排列


 
SELECT product_id, product_name, sale_price, purchase_price
 
FROM Product
 
ORDER BY purchase_price;

执行结果

NULL 的顺序

究竟是在开头显示还是在末尾显示,并没有特殊规定。某些 DBMS 中可以指定 NULL 在开头或末尾显示,希望大家对自己使用的 DBMS 的功能研究一下。

法则 17

排序键中包含 NULL 时,会在开头或末尾进行汇总。

五、在排序键中使用显示用的别名

在 对表进行分组 中“常见错误 ②”中曾介绍过,在 GROUP BY 子句中不能使用 SELECT 子句中定义的别名,但是在 ORDER BY 子句中却是允许使用别名的。因此,代码清单 32 中的 SELECT 语句并不会出错,可正确执行。

代码清单 32 ORDER BY 子句中可以使用列的别名


 
SELECT product_id AS id, product_name, sale_price AS sp, purchase_price
 
FROM Product
 
ORDER BY sp, id;

上述 SELECT 语句与之前按照“销售单价和商品编号的升序进行排列”的 SELECT 语句(代码清单 31)意思完全相同。

执行结果


 
id | product_name | sp | purchase_price
 
------+---------------+-------+---------------
 
0008 | 圆珠笔 | 100 |
 
0002 | 打孔器 | 500 | 320
 
0006 | 叉子 | 500 |
 
0007 | 擦菜板 | 880 | 790
 
0001 | T恤衫 | 1000 | 500
 
0004 | 菜刀 | 3000 | 2800
 
0003 | 运动T恤 | 4000 | 2800
 
0005 | 高压锅 | 6800 | 5000
 
 

不能在 GROUP BY 子句中使用的别名,为什么可以在 ORDER BY 子句中使用呢?这是因为 SQL 语句在 DBMS 内部的执行顺序被掩盖起来了。SELECT 语句按照子句为单位的执行顺序如下所示。

▶ 使用 HAVING 子句时 SELECT 语句的顺序

FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY

这只是一个粗略的总结,虽然具体的执行顺序根据 DBMS 的不同而不同,但是大家有这样一个大致的印象就可以了。一定要记住 SELECT 子句的执行顺序在 GROUP BY 子句之后,ORDER BY 子句之前。因此,在执行 GROUP BY 子句时,SELECT 语句中定义的别名无法被识别 [1]。对于在 SELECT 子句之后执行的 ORDER BY 子句来说,就没有这样的问题了。

法则 18

在 ORDER BY 子句中可以使用 SELECT 子句中定义的别名。

六、ORDER BY 子句中可以使用的列

ORDER BY 子句中也可以使用存在于表中、但并不包含在 SELECT 子句之中的列(代码清单 33)。

代码清单 33 SELECT 子句中未包含的列也可以在 ORDER BY 子句中使用


 
SELECT product_name, sale_price, purchase_price
 
FROM Product
 
ORDER BY product_id;

执行结果


 
product_name | sale_price | purchase_price
 
---------------+-------------+----------------
 
T恤衫 | 1000 | 500
 
打孔器 | 500 | 320
 
运动T恤 | 4000 | 2800
 
菜刀 | 3000 | 2800
 
高压锅 | 6800 | 5000
 
叉子 | 500 |
 
擦菜板 | 880 | 790
 
圆珠笔 | 100 |
 
 

除此之外,还可以使用聚合函数(代码清单 34)。

代码清单 34 ORDER BY 子句中也可以使用聚合函数

ORDER BY 子句中也可以使用聚合函数

执行结果


 
product_type | count
 
---------------+------
 
衣服 | 2
 
办公用品 | 2
 
厨房用具 | 4

法则 19

在 ORDER BY 子句中可以使用 SELECT 子句中未使用的列和聚合函数。

七、不要使用列编号

在 ORDER BY 子句中,还可以使用在 SELECT 子句中出现的列所对应的编号,是不是没想到?列编号是指 SELECT 子句中的列按照从左到右的顺序进行排列时所对应的编号(1, 2, 3,…)。因此,代码清单 35 中的两条 SELECT 语句的含义是相同的。

KEYWORD

  • 列编号

代码清单 35 ORDER BY 子句中可以使用列的编号


 
-- 通过列名指定
 
SELECT product_id, product_name, sale_price, purchase_price
 
FROM Product
 
ORDER BY sale_price DESC, product_id;
 
 
 
-- 通过列编号指定
 
SELECT product_id, product_name, sale_price, purchase_price
 
FROM Product
 
ORDER BY 3 DESC, 1;

上述第 2 条 SELECT 语句中的 ORDER BY 子句所代表的含义,就是“按照 SELECT 子句中第 3 列的降序和第 1 列的升序进行排列”,这和第 1 条 SELECT 语句的含义完全相同。

执行结果


 
product_id | product_name | sale_price | purchase_price
 
-----------+---------------+-------------+----------------
 
0005 | 高压锅 | 6800 | 5000
 
0003 | 运动T恤 | 4000 | 2800
 
0004 | 菜刀 | 3000 | 2800
 
0001 | T恤衫 | 1000 | 500
 
0007 | 擦菜板 | 880 | 790
 
0002 | 打孔器 | 500 | 320
 
0006 | 叉子 | 500 |
 
0008 | 圆珠笔 | 100 |
 
 

虽然列编号使用起来非常方便,但我们并不推荐使用,原因有以下两点。

第一,代码阅读起来比较难。使用列编号时,如果只看 ORDER BY 子句是无法知道当前是按照哪一列进行排序的,只能去 SELECT 子句的列表中按照列编号进行确认。上述示例中 SELECT 子句的列数比较少,因此可能并没有什么明显的感觉。但是在实际应用中往往会出现列数很多的情况,而且 SELECT 子句和 ORDER BY 子句之间,还可能包含很复杂的 WHERE 子句和 HAVING 子句,直接人工确认实在太麻烦了。

第二,这也是最根本的问题,实际上,在 SQL-92 [2] 中已经明确指出该排序功能将来会被删除。因此,虽然现在使用起来没有问题,但是将来随着 DBMS 的版本升级,可能原本能够正常执行的 SQL 突然就会出错。不光是这种单独使用的 SQL 语句,对于那些在系统中混合使用的 SQL 来说,更要极力避免。

法则 20

在 ORDER BY 子句中不要使用列编号。

请参阅

  • 对表进行聚合查询
  • 对表进行分组
  • 为聚合结果指定条件
  • 对查询结果进行排序

(完)


  1. 也是因为这一原因,HAVING 子句也不能使用别名。 ↩︎

  2. 1992 年制定的 SQL 标准。 ↩︎

    来源:
    https://www.cnblogs.com/vin-c/p/15568265.html


相关教程