PostgreSQL中如何为Rank函数加条件:Admin固定设为0排名
分组排名优化方案:Admin固定为0,其余正常排序
需求回顾
现有表包含name、start_date、group_no字段,需要实现:
- 按
group_no分组 - 每组内按
start_date降序排名 - 名为
Admin的记录排名强制为0,其余记录排名从1开始连续递增
问题分析
- 直接用
RANK()/ROW_NUMBER()无法单独将Admin的排名固定为0 - 简单用
CASE语句会导致非Admin的排名从2开始(因为窗口函数会把Admin纳入计数) - 用
UNION可以实现,但可以通过更简洁的窗口函数组合优化
最优解决方案1:窗口函数组合修正排名
通过统计组内Admin的数量,对非Admin的排名做偏移修正,避免额外的表扫描:
SELECT name, start_date, group_no, CASE WHEN name = 'Admin' THEN 0 ELSE ROW_NUMBER() OVER (PARTITION BY group_no ORDER BY start_date DESC) - SUM(CASE WHEN name = 'Admin' THEN 1 ELSE 0 END) OVER (PARTITION BY group_no) END AS rank_no FROM your_table ORDER BY group_no, rank_no;
逻辑说明
ROW_NUMBER() OVER (...):给每组内所有记录(包括Admin)按start_date降序生成从1开始的连续编号SUM(...) OVER (...):统计每组内Admin的数量(支持组内多个Admin的场景)- 非Admin的排名用基础行号减去组内Admin的数量,抵消Admin占用的编号位,确保从1开始
最优解决方案2:高效版UNION ALL
如果每组Admin数量少,用UNION ALL(比UNION快,因为不做去重)拆分逻辑,更直观:
-- 提取Admin记录,直接设排名为0 SELECT name, start_date, group_no, 0 AS rank_no FROM your_table WHERE name = 'Admin' UNION ALL -- 提取非Admin记录,正常按组生成排名 SELECT name, start_date, group_no, ROW_NUMBER() OVER (PARTITION BY group_no ORDER BY start_date DESC) AS rank_no FROM your_table WHERE name != 'Admin' ORDER BY group_no, rank_no;
优势
- 逻辑清晰,容易维护
UNION ALL避免了UNION的去重开销,性能更优
内容的提问来源于stack exchange,提问作者Adarsh Ravi
相关产品推荐
相关产品推荐

