order by多列排序严格按从左到右逐级生效:先按首字段排序,值相同时才用次字段排序;顺序错误会导致业务逻辑失效,如“每状态最新记录”必须写为order by status, created_at desc而非反序。

ORDER BY 多列排序不是“一起排”,而是严格按从左到右逐级生效——左边字段值不同时,右边字段根本不会参与比较。写错顺序,SQL 仍能执行,但业务逻辑就悄悄崩了。
ORDER BY 字段顺序直接决定分组逻辑
比如要查「每个状态里最新的一条记录」,必须写成 ORDER BY status, created_at DESC:先按 status 分大组,每组内再按时间倒序。如果写反成 ORDER BY created_at DESC, status,结果就是所有记录按时间从新到旧排,status 只在时间相同时起作用,完全偏离本意。
- 字段位置 = 优先级:第一个字段是主排序依据,第二个是“同主值时的次级规则”
- 验证方法:挑几行
status相同的数据,看它们是否真按created_at DESC排 - 别用数字位置(如
ORDER BY 1, 3 DESC),SELECT 列一改,排序就失效
CASE WHEN 在 ORDER BY 中必须显式处理所有分支
当需要「先按状态分组(pending→approved→rejected),组内再按时间倒序」时,CASE WHEN 是最直接解法,但漏写 ELSE 或类型不一致会出问题。
- 每个
WHEN和ELSE必须返回相同类型(推荐统一用整数) - 没写
ELSE→ 未匹配行变成NULL,默认排最前,常导致'rejected'记录意外顶到顶部 - 字段本身可能为
NULL(如reviewer_id IS NULL),优先用CASE WHEN reviewer_id IS NULL THEN 0 ELSE 1 END而不是直接比较
NULL 值排序必须显式声明 NULLS FIRST/LAST
不同数据库对 NULL 的默认行为不一致:PostgreSQL 默认 NULLS LAST,MySQL 默认 NULLS FIRST。不显式写,开发和生产环境排序结果可能完全不同。
-
NULLS FIRST或NULLS LAST必须紧跟在对应排序项后,不能全局生效 - 例如让「未分配审核人」排最前,且不影响后续时间排序:
ORDER BY CASE WHEN reviewer_id IS NULL THEN 0 ELSE 1 END, created_at DESC NULLS LAST - MySQL 8.0+ 支持该语法,老版本只能靠
reviewer_id IS NULL布尔表达式模拟
表达式排序必须配函数索引,否则性能陡降
带 CASE WHEN、LENGTH() 或计算字段的 ORDER BY 无法走普通 B-tree 索引。高频查询(如后台订单列表)中,响应延迟会随数据量线性上升。
- PostgreSQL 示例:
CREATE INDEX idx_orders_status_time ON orders ((CASE WHEN status = 'pending' THEN 1 ELSE 2 END), created_at DESC); - MySQL 8.0+ 类似,需用函数索引语法:
CREATE INDEX idx_orders_status_time ON orders ((CASE WHEN status = 'pending' THEN 1 ELSE 2 END), created_at DESC); - SQLite 不支持函数索引,这类排序尽量避免在大数据量表上使用
NULL 处理——它们不报错,但会让排序结果在不同环境或数据分布下悄然变化。











