CASE 自定义排序是什么
按业务枚举排序(紧急 高于 高 高于 普通)不能用字母序或拼音序,通用做法是用 CASE 表达式把枚举映射成数字序号,再放进 ORDER BY 参与排序。两个要点:必须补次级排序键(时间或主键),保证同优先级内的顺序稳定,否则翻页会出现重复或漏行;映射值较多或经常变化时应改用维度表存排序号,把规则集中管理,而不是散落在多条 SQL 里。
基本信息
| 适用平台 | MySQL 8.0 / PostgreSQL / SQL Server / Oracle |
|---|---|
| 原理 | 把枚举映射为可比较的序号,交给 ORDER BY 排序 |
| 次级排序 | 同优先级内用时间或主键列定序,保证结果稳定 |
| 替代方案 | 冗余 sort_no 列(可建索引)、维度表关联排序、PostgreSQL 枚举类型 |
| 性能代价 | 排序列是表达式,通常无法直接使用该列的索引用途 |
典型使用场景
- 工单、告警按优先级排序(紧急优先展示)
- 订单按业务流转顺序排列,而不是按状态字符串
- 报表维度按自定义顺序输出(如大区按业务重要性排列)
- 多级排序的第一级:先按自定义优先级,再按时间
- 与分组统计配合,让输出顺序固定、便于人工核对
排序写法
排序写法
SELECT id, title, priority, created_at
FROM tickets
ORDER BY CASE priority
WHEN 'urgent' THEN 0
WHEN 'high' THEN 1
WHEN 'normal' THEN 2
ELSE 3 # 未覆盖的取值统一落到最后
END,
created_at DESC, # 次级排序:同优先级按时间倒序
id DESC; # 兜底唯一键,保证翻页稳定
-- 直接按排序号排序(冗余列方案,可走索引)
SELECT id, title FROM tickets ORDER BY sort_no, created_at DESC;几种实现方式对比
| 做法 | 优点 | 代价 |
|---|---|---|
| CASE 表达式 | 不改表结构,随时调整顺序 | 无法用列索引,映射散落在 SQL 里 |
| 冗余 sort_no 列 + 索引 | SQL 简单,可走索引 | 需要维护数据一致性 |
| 维度表关联排序 | 映射集中管理 | 多一次连接 |
| 枚举类型(PG) | 定义顺序即排序规则 | 类型定义变更成本较高 |
PostgreSQL 的枚举类型按 CREATE TYPE 时的定义顺序比较;MySQL 的 ENUM 列排序按内部编号(也是定义顺序)进行,两者都能把定义顺序直接当成排序规则,差别在新增取值时需要改 DDL 而不是改 SQL。
排序列套了 CASE 表达式后基本无法走索引,高频列表页每次都要计算并排序;数据量大时建议冗余 sort_no 列并建索引,把表达式排序换成索引排序。