ORDER BY 排序
本教程共 50 篇 · 第 26 篇 · 更新于 2026-07-31 · 约 8 分钟阅读
26. ORDER BY 排序
本节目标:学会用 ORDER BY 给查询结果排序,掌握升序降序、多列排序、按别名/表达式排序,以及控制 NULL 的位置。
SELECT 查出来的行,默认顺序是”未指定”的,可能每次都不同。想按某一列有序展示,就得用 ORDER BY。
先用示例的 users 表做演示:
CREATE TABLE users (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
username VARCHAR(50),
email VARCHAR(100),
age INT,
created_at DATE
);
INSERT INTO users (username, email, age, created_at) VALUES
('alice', 'alice@example.com', 28, '2025-01-12'),
('bob', 'bob@example.com', 35, '2025-03-08'),
('charlie','charlie@example.com',19, '2025-05-20'),
('dave', 'dave@example.com', 42, '2025-07-01'),
('emma', NULL, 31, '2025-09-15');
升序 ASC 与降序 DESC
ORDER BY 列名 默认按升序(从小到大)排。显式写 ASC 效果一样;要倒过来就写 DESC。
-- 按年龄从大到小排
SELECT username, age
FROM users
ORDER BY age DESC;
Note文本类型按字符集顺序排,数字和日期按大小排。
ASC是默认值,不写也行。
多列排序
ORDER BY 后面可以跟多列,用逗号分开。排序时先按第一列排,第一列相同的行,再按第二列排,依此类推。
-- 先按年龄升序,年龄相同再按用户名降序
SELECT username, age
FROM users
ORDER BY age ASC, username DESC;
注意顺序很重要:把哪一列放前面,它就主导排序。放后面的列只在”前面列值相等”时才起作用。比如两个人同龄时,用户名才会决定谁在前。
按别名排序
SELECT 里起的列别名(alias),可以直接在 ORDER BY 里用。这是因为 PostgreSQL 先算 SELECT,再排 ORDER BY,别名那时已经存在了。
-- 给年龄起别名,再按别名排
SELECT username, age AS user_age
FROM users
ORDER BY user_age DESC;
按表达式排序
排序依据不限于某一列,也可以是一个表达式。比如按用户名的长度排:
-- LENGTH() 返回字符串长度,按长度从长到短排
SELECT username, LENGTH(username) AS name_len
FROM users
ORDER BY name_len DESC;
Tip表达式排序很灵活,但也意味着数据库要对每行算一遍表达式。列多、数据大时留意性能,必要时刻考虑冗余存一列或建函数索引。
NULLS FIRST / LAST 控制空值位置
NULL 表示”没有值”。排序时,空值排前面还是后面,可以用 NULLS FIRST 或 NULLS LAST 明确指定。
-- 把 email 为空的行排到最后
SELECT username, email
FROM users
ORDER BY email NULLS LAST;
默认规则要记一下:升序(ASC)时空值在最后(NULLS LAST),降序(DESC)时空值在最前(NULLS FIRST)。如果你想要反过来的效果,就显式写出来:
-- 降序但让空值留在最后
SELECT username, email
FROM users
ORDER BY email DESC NULLS LAST;
Warning不同数据库对 NULL 的默认排序位置可能不同。写跨库 SQL 时,建议显式带上
NULLS FIRST/LAST,避免行为不一致。
用列位置数字排序
ORDER BY 后面除了写列名,还能写数字,代表 SELECT 里第几列(从 1 开始)。写起来快,但可读性差:
-- 等价于 ORDER BY username, age
SELECT username, age
FROM users
ORDER BY 1, 2;
Warning用数字排序很容易踩坑:一旦调整了 SELECT 的列顺序,ORDER BY 的数字没跟着改,排序就偷偷变了。生产代码建议老老实实写列名。
随机打乱顺序
想让结果随机排序,可以用 RANDOM() 函数(返回 0~1 的随机数)。常配合 LIMIT 做”随机抽几条”:
-- 随机抽 2 个用户
SELECT username
FROM users
ORDER BY RANDOM()
LIMIT 2;
Note
RANDOM()排序要对全表打乱,数据量大时很慢,别在频繁查询里用。它和LIMIT搭配做”随机取样”很顺手。
常见错误
- 把
ORDER BY写在WHERE前面会报语法错,顺序必须是WHERE先、ORDER BY后。 - 想”先按某列升序、再按某列降序”,却两列都写成
DESC,导致顺序不符合预期。 - 文本排序依赖数据库的字符集(collation),中文按拼音还是按笔画由排序规则决定,换环境可能不同,需要稳定顺序时显式指定。
- 用数字位置排序后改了 SELECT 列,却忘了改数字,排序结果静默出错。
ORDER BY + LIMIT 取”前 N 名”
排序最常见的搭配就是取榜单前几名:
-- 年龄最大的 3 位用户
SELECT username, age
FROM users
ORDER BY age DESC
LIMIT 3;
如果第 3 名有并列,LIMIT 3 会随机丢几个。想要”并列都保留”,用上一章讲的 FETCH FIRST ... WITH TIES,或者把打破平局的列也写进 ORDER BY,让顺序唯一。
每列单独指定方向与前导
ORDER BY 后面每一列都能单独指定升/降和 NULL 位置,互不影响:
-- 先按状态原样排,再按金额降序、空值留最后
SELECT id, status, amount
FROM orders
ORDER BY status ASC, amount DESC NULLS LAST;
排序和索引
如果 ORDER BY 的列上建了索引,PostgreSQL 有时能直接按索引顺序读,省掉一次额外排序。但表达式排序(如 LENGTH(username))一般吃不到普通索引,除非建对应的函数索引。
Warning排序发生在所有过滤之后。数据量大又没索引可借力时,ORDER BY 可能触发一次全量排序(必要时落盘),是慢查询的常见来源,要留意。
Note补充一点:ORDER BY 不只用在普通查询里,子查询、CTE、甚至配合 UPDATE / DELETE 也能用。它的核心是”决定返回或处理的顺序”,理解了这个,哪里都能灵活用。
小结
ORDER BY 列默认升序,DESC改降序。- 多列用逗号分隔,前面的列主导排序,后面的列只在前面列相等时生效。
- 可按
SELECT里的别名或表达式排序。 - 用
NULLS FIRST/LAST控制空值位置,默认 ASC 空值在尾、DESC 空值在头。 - 列位置数字排序易错,随机排序
RANDOM()在大表上偏慢。