本节摘要:ORDER BY 对查询结果排序。本节讲单列排序、升降序、多列排序、按表达式排序,以及排序的几个注意点。
阅读完本节,你应当能够:
第 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 放哪因 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 最好带唯一列保证稳定。
下一节讲分页——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 变通)。先了解默认行为,再按需显式控制。
排序的要点,适合用一组对比实验来掌握。
准备一张练习表,插入若干行数据,其中包含:重复值、空值、中文值、英文值。
第一个练习:不写排序子句查询一次,连续跑几遍,观察返回顺序是否每次都一样。如果不一样,你就亲眼验证了"不排序顺序不保证"这个结论;如果一样,也别大意,那只是当前数据量下的巧合。
第二个练习:分别用升序和降序排一遍,再试试多列排序,观察第一列相同时第二列如何决定顺序。
第三个练习:让某列含有空值,分别用升序和降序查看空值出现在开头还是结尾。如果发现和你预期不符,就理解了对空值位置要显式处理的原因。
第四个练习:试试用选择别名排序、用表达式排序,感受排序阶段可以引用哪些东西。
这四个练习做完,你对"为什么必须显式排序""多列排序的规则""空值的排序位置"会有切身体会。排序是查询里最常用也最容易想当然的环节,动手验证一遍,比记住十条结论都实在。
关系模型里的行天生无序,想要稳定顺序就必须显式排序。单列排序最简单,多列排序前列优先,空值位置各库不同需要显式处理。