MySQL 零基础教程

MySQL ORDER BY 语句

从数据库中检索数据时,结果返回的顺序会极大地影响数据的可用性和分析效率。SQL 中的 ORDER BY 子句允许你根据一个或多个指定的列,对 SELECT 语句的结果集进行排序。该子句赋予了你控制数据呈现方式的能力,可以按升序或降序排列数据。

1. 使用 ORDER BY 进行基础排序

ORDER BY 最基础的用法是指定单个列进行排序。默认情况下,ORDER BY 会按升序对结果进行排序。为了明确定义排序顺序,你可以使用 ASC 关键字表示升序,或使用 DESC 关键字表示降序。

1.1 单列升序排序

当你按升序排序时,数值会从最小排列到最大,字母字符串从 A 排列到 Z,日期从最旧排列到最新。

示例 1:按姓名对客户进行排序
假设有一个名为 customers(客户)的表,包含 customer_idfirst_namelast_namecity 等列。要检索所有客户并按他们的姓氏字母顺序排序:

SELECT
    customer_id,
    first_name,
    last_name,
    city
FROM
    customers
ORDER BY
    last_name ASC; -- 明确指定按 last_name(姓氏)进行升序排序

这个查询会返回所有客户的详细信息,但行的排列方式是:姓氏以 'A' 开头的客户排在最前面,接着是 'B',以此类推。

示例 2:按价格对产品进行排序
想象一个包含 product_idproduct_namepriceproducts(产品)表。要将产品从最便宜到最贵列出:

SELECT
    product_id,
    product_name,
    price
FROM
    products
ORDER BY
    price; -- ASC 是默认值,因此可以省略

输出结果会先显示价格较低的产品,然后逐步过渡到价格较高的商品。

1.2 单列降序排序

降序排列会反转排序规则:数值从最大排列到最小,字母字符串从 Z 排列到 A,日期从最新排列到最旧。

示例 3:按入职日期对员工进行排序
一个名为 employees(员工)的表可能包含 employee_idfirst_namelast_namehire_date。要首先查看最近入职的员工:

SELECT
    employee_id,
    first_name,
    last_name,
    hire_date
FROM
    employees
ORDER BY
    hire_date DESC; -- 按 hire_date(入职日期)进行降序排序

这个查询会呈现员工列表,从最近雇佣的员工开始。

示例 4:按数量查找最畅销的商品
如果一个 sales(销售)表包含 item_idquantity_sold(售出数量),要首先识别出销量最高的商品:

SELECT
    item_id,
    quantity_sold
FROM
    sales
ORDER BY
    quantity_sold DESC;

结果将显示按 quantity_sold 从高到低排序的商品。

2. 多列排序

你可以在 ORDER BY 子句中指定多个列。提供多个列时,数据库会首先按照最左边指定的列进行排序。如果第一列中存在相同的值,数据库接着会使用第二列对这些行进行排序,依此类推。ORDER BY 子句中的每一列都可以有自己独立的 ASCDESC 说明符。

示例 5:先按城市排序,再按姓氏排序
要将客户首先按他们所在的城市进行组织,然后对于同一城市内的客户,按他们的姓氏进行排序:

SELECT
    customer_id,
    first_name,
    last_name,
    city
FROM
    customers
ORDER BY
    city ASC,        -- 首先按 city(城市)进行升序排序
    last_name ASC;   -- 然后对每个城市内的客户按 last_name(姓氏)进行升序排序

这个查询会将所有来自 'New York' 的客户聚集在一起并按姓氏排序,接着是所有来自 'London' 的客户并按姓氏排序,以此类推。

示例 6:按订单状态(降序)然后按订单日期(降序)排序
考虑一个带有 order_idcustomer_idorder_dateorder_statusorders(订单)表。要先看到最近完成的订单,再看待处理的订单,并且在相同状态下优先看最新的订单:

SELECT
    order_id,
    customer_id,
    order_date,
    order_status
FROM
    orders
ORDER BY
    order_status DESC, -- 按状态排序(例如,'Completed' 排在 'Pending' 之前)
    order_date DESC;   -- 然后按 order_date 排序(最新的优先)

如果 order_status 是一个字符串,在升序中 'Completed' 会排在 'Pending' 之后。在这里使用 DESC 会将 'Pending' 排在 'Completed' 之前(如果这是你想要的逻辑分组);或者如果使用的是状态代码(例如,1 代表待处理,2 代表已完成),DESC 就会将已完成 (2) 排在待处理 (1) 之前。

3. 按列位置排序

除了通过列名来引用列之外,你还可以通过它们在 SELECT 列表中的位置来引用它们。这种做法可读性较差,通常不推荐在生产环境查询中使用,因为对 SELECT 列表的更改(添加或删除列)可能会导致查询出错。不过,这是一种有效的语法。

示例 7:按列位置排序
使用示例 3 中的 employees 表:

SELECT
    employee_id, -- 第 1 列
    first_name,  -- 第 2 列
    last_name,   -- 第 3 列
    hire_date    -- 第 4 列
FROM
    employees
ORDER BY
    4 DESC; -- 按 SELECT 列表中的第 4 列(即 hire_date)进行降序排序

这个查询实现了与示例 3 相同的结果,但使用了列位置 4 而不是 hire_date

4. 结合 WHERE 子句排序

SELECT 语句中同时使用 WHEREORDER BY 时,ORDER BY 子句通常放置在 WHERE 子句之后。数据库会先使用 WHERE 子句过滤行,然后再使用 ORDER BY 对过滤后的结果集进行排序。

示例 8:过滤并排序客户
仅检索来自 'New York' 的客户,并按他们的姓氏排序:

SELECT
    customer_id,
    first_name,
    last_name,
    city
FROM
    customers
WHERE
    city = 'New York' -- 过滤出位于纽约的客户
ORDER BY
    last_name ASC;    -- 然后将过滤后的结果按姓氏排序

此查询首先选择 city 为 'New York' 的所有客户,然后再将仅有的这些特定客户按姓氏的字母顺序排列。这演示了 WHERE 子句如何在 ORDER BY 组织数据之前先缩小数据范围。

5. NULL 值与排序

当对包含 NULL(空)值的列进行排序时,不同数据库系统处理 NULL 的行为可能会有所不同。在 MySQL 中,排序时 NULL 值被视为最低可能的值。因此,在 ASC(升序)排序中它们会出现在最前面,而在 DESC(降序)排序中它们会出现在最后面。

示例 9:包含 NULL 值的排序
考虑一个 employees 表,其中包含一个 manager_id 列,对于最高层级的员工,该列可能为 NULL

SELECT
    employee_id,
    first_name,
    manager_id
FROM
    employees
ORDER BY
    manager_id ASC; -- NULL 值将首先出现

在升序排列中,manager_idNULL 的员工(通常是高层管理人员)将被列在最前面。

SELECT
    employee_id,
    first_name,
    manager_id
FROM
    employees
ORDER BY
    manager_id DESC; -- NULL 值将最后出现

在降序排列中,manager_idNULL 的员工将被列在最后面。

在解释排序结果时,这种行为非常重要,特别是当处理 NULL 代表“未知”或“不适用”的列时。