-
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
- 排序键
▶ 子句的书写顺序
-
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; |
执行结果
究竟是在开头显示还是在末尾显示,并没有特殊规定。某些 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
子句中也可以使用聚合函数
执行结果
|
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
子句中不要使用列编号。
请参阅
- 对表进行聚合查询
- 对表进行分组
- 为聚合结果指定条件
- 对查询结果进行排序
(完)
-
也是因为这一原因,
HAVING
子句也不能使用别名。 ↩︎ -
1992 年制定的 SQL 标准。 ↩︎
来源:https://www.cnblogs.com/vin-c/p/15568265.html