3.3 ORDER BY 结果排序


3.3 ORDER BY 结果排序

本节摘要:ORDER BY 对查询结果排序。本节讲单列排序、升降序、多列排序、按表达式排序,以及排序的几个注意点。

本节导航

阅读完本节,你应当能够:

  1. 用 ORDER BY 排序结果
  2. 区分 ASC 升序和 DESC 降序
  3. 用多列排序
  4. 理解 NULL 在排序中的位置

一、为什么必须显式排序

第 2 章讲过,关系模型里行是无序的。SELECT 不加 ORDER BY,返回顺序不保证——可能按插入顺序、可能按索引顺序、可能每次不同。要稳定顺序,必须显式 ORDER BY。

SELECT FirstName, City FROM Customers ORDER BY City;

二、升降序

默认升序(ASC,从小到大)。用 DESC 指定降序(从大到小):

SELECT * FROM Orders ORDER BY Amount DESC; -- 金额从大到小 SELECT * FROM Customers ORDER BY City ASC; -- 城市升序(ASC 可省略)
关键字 顺序 适用
ASC 升序(小→大) 默认,可省略
DESC 降序(大→小) 显式指定

三、多列排序

按多列排序,前面的优先,相同再按后面的:

SELECT * FROM Orders ORDER BY CustomerID ASC, Amount DESC;

先按 CustomerID 升序,CustomerID 相同的再按 Amount 降序。每个列可独立指定 ASC/DESC。

四、按表达式和别名排序

ORDER BY 在 SELECT 之后执行,所以可以用 SELECT 起的别名或表达式:

SELECT FirstName, Amount * 1.1 AS 含税 FROM Orders ORDER BY 含税 DESC; -- 用别名排序 SELECT FirstName, LastName FROM Customers ORDER BY LENGTH(FirstName); -- 按名字长度排

五、NULL 的位置

排序时 NULL 放哪因 DBMS 而异:MySQL 里 ASC 时 NULL 在前、DESC 在后;PostgreSQL 相反;SQL Server 默认 ASC 时 NULL 在前。要明确控制可用 NULLS FIRST/NULLS LAST(部分 DBMS 支持)或用 IS NULL 配合。

⚠️ 常见坑:分页查询不加 ORDER BY,结果每页可能重复或漏数据——因为顺序不定。分页必须配稳定的 ORDER BY,最好按唯一列(如主键)兜底。

💡 关键直觉:要稳定顺序就显式 ORDER BY,多列排序前面优先,ORDER BY 可用 SELECT 别名。分页查询的 ORDER BY 最好带唯一列保证稳定。

一节小结

  • 必须显式排序:关系无序,不加 ORDER BY 顺序不保证。
  • 升降序:ASC 升序(默认)、DESC 降序,每列独立指定。
  • 多列排序:前面优先,相同再按后面。
  • 可用别名/表达式:ORDER BY 在 SELECT 后执行,能用别名和计算。
  • NULL 位置:因 DBMS 而异,要明确控制用 NULLS FIRST/LAST 或 IS NULL 配合。
  • 分页查询的 ORDER BY 带唯一列保证稳定。

下一节讲分页——LIMIT 和 OFFSET。

常见疑问

Q1:不加 ORDER BY 结果顺序为什么不固定?

关系模型规定行是无序的。数据库为了提高性能可能用并行、不同扫描路径,每次返回顺序都可能不同。写程序时如果假设"顺序是插入顺序",一旦数据量变大或优化器策略变化,程序就出 bug。所以凡是对顺序有要求的查询,必须显式 ORDER BY

Q2:中文排序按什么排?

按数据库的排序规则(collation)。MySQL 默认 utf8mb4_general_ci 按 Unicode 码点排,中文会按拼音(大致)排;PostgreSQL 依赖系统 locale。想按特定规则排(如拼音、笔画)需要设置对应的排序规则,这是高级话题。入门只需知道:中文排序默认"看起来像按拼音",但可能不稳定,对顺序敏感要显式处理。

Q3:多列排序怎么理解"前面的优先"?

先按第一列排序,第一列相同的行再按第二列排,依此类推。ORDER BY City, Amount DESC 表示先按城市,同一城市内金额从高到低。可以理解为"嵌套排序"。注意每一列都可以独立指定 ASC/DESC。

Q4:排序字段上建索引有用吗?

有用。如果排序字段(或复合排序前缀)有索引,数据库可以直接按索引顺序读,避免额外排序(filesort),性能更好。但要注意:ORDER BY 和 WHERE 组合时,索引要能同时服务两者才有效,这是索引设计的话题,第 7 章会深入。

Q5:NULL 排序位置怎么控制?

不同数据库默认不同:MySQL 里 ASC 时 NULL 在前,PostgreSQL 相反。想明确控制,可用 ORDER BY col NULLS LAST(PostgreSQL/SQL Server 支持)或 ORDER BY ISNULL(col), col(MySQL 变通)。先了解默认行为,再按需显式控制。

动手做一做

排序的要点,适合用一组对比实验来掌握。

准备一张练习表,插入若干行数据,其中包含:重复值、空值、中文值、英文值。

第一个练习:不写排序子句查询一次,连续跑几遍,观察返回顺序是否每次都一样。如果不一样,你就亲眼验证了"不排序顺序不保证"这个结论;如果一样,也别大意,那只是当前数据量下的巧合。

第二个练习:分别用升序和降序排一遍,再试试多列排序,观察第一列相同时第二列如何决定顺序。

第三个练习:让某列含有空值,分别用升序和降序查看空值出现在开头还是结尾。如果发现和你预期不符,就理解了对空值位置要显式处理的原因。

第四个练习:试试用选择别名排序、用表达式排序,感受排序阶段可以引用哪些东西。

这四个练习做完,你对"为什么必须显式排序""多列排序的规则""空值的排序位置"会有切身体会。排序是查询里最常用也最容易想当然的环节,动手验证一遍,比记住十条结论都实在。

一句话记忆

关系模型里的行天生无序,想要稳定顺序就必须显式排序。单列排序最简单,多列排序前列优先,空值位置各库不同需要显式处理。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U