如何使用row_number()函数或其他方式实现特定规则的数据排序?
按状态变更分组排序的解决方案
看起来你需要把同一个req_no下的记录,按照状态变更的批次来分组排序——也就是每次s_type <> e_type(状态发生变更)时,开启一个新的排序分组,对吧?我给你提供一个基于窗口函数的实现方案,几乎所有支持SQL窗口函数的数据库(PostgreSQL、MySQL 8.0+、SQL Server等)都能用。
核心思路
我们可以通过累计状态变更的次数来生成sort_type列:
- 先标记每一行是否是状态变更节点(
s_type <> e_type时记为1,否则0) - 对每个
req_no分组,按seq顺序累计这个标记值,再加1就得到了sort_type(确保分组从1开始) - 最后用
ROW_NUMBER()基于sort_type和seq排序,得到最终的排序结果
完整SQL代码
WITH status_groups AS ( SELECT req_no, seq, s_date, e_date, s_type, e_type, -- 生成sort_type:累计状态变更次数+1 1 + SUM(CASE WHEN s_type <> e_type THEN 1 ELSE 0 END) OVER ( PARTITION BY req_no ORDER BY seq ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS sort_type FROM your_table_name ) SELECT *, -- 最终排序号:按sort_type分组,再按seq排序 ROW_NUMBER() OVER ( PARTITION BY req_no ORDER BY sort_type, seq ) AS final_sort_no FROM status_groups ORDER BY req_no, final_sort_no;
针对你提供的测试数据的输出结果
假设你的数据行5是s_type=01, e_type=01,运行后会得到这样的结果:
| req_no | seq | s_date | e_date | s_type | e_type | sort_type | final_sort_no |
|---|---|---|---|---|---|---|---|
| 001 | 1 | 2017-01-01 | 2017-01-02 | 01 | 01 | 1 | 1 |
| 001 | 2 | 2017-01-02 | 2017-01-02 | 01 | 02 | 2 | 2 |
| 001 | 3 | 2017-01-02 | 2017-01-02 | 02 | 02 | 2 | 3 |
| 001 | 4 | 2017-01-02 | 2017-01-02 | 02 | 01 | 3 | 4 |
| 001 | 5 | ... | ... | 01 | 01 | 3 | 5 |
关键细节说明
PARTITION BY req_no:确保每个请求的记录单独处理,不会和其他req_no的数据混在一起ORDER BY seq:保证我们是按原始的seq顺序来累计状态变更的,符合业务逻辑- 如果你的数据库不支持CTE(WITH子句),可以把逻辑合并成一个子查询,效果是一样的
内容的提问来源于stack exchange,提问作者nettoon493




