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,但是省略該關鍵字時會默認使用升序進行排序。這可能是因為實際應用中按照升序排序的情況更多吧。ASCDESC 是 ascendent(上升的)和 descendent(下降的)這兩個單詞的縮寫。

KEYWORD

  • ASC 關鍵字

法則 16

未指定 ORDER BY 子句中排列順序時會默認使用升序進行排列。

由於 ASCDESC 這兩個關鍵字是以列為單位指定的,因此可以同時指定一個列為升序,指定其他列為降序。

三、指定多個排序鍵

本節開頭曾提到過對銷售單價進行升序排列的 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 語句的順序

FROMWHEREGROUP BYHAVINGSELECTORDER 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 標准。 ↩︎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM