使用DENSE_RANK()的SQL查询:提取Top5客户的全部数据
解决方案
你的核心问题是当前的DENSE_RANK()是基于单条记录计算的,导致同一客户出现多个排名值。要提取Top5客户的全部记录,必须先按客户维度计算排名,再筛选出排名前5的客户的所有数据。以下是两种实用写法:
方法1:先聚合客户排名,再关联筛选
WITH customer_gp_rank AS ( -- 先按客户聚合,计算每个客户2022年总毛利润并排名 SELECT customer_id, customer_name, SUM(CASE WHEN year = 2022 THEN gross_profit ELSE 0 END) AS total_2022_gross_profit, DENSE_RANK() OVER(ORDER BY SUM(CASE WHEN year = 2022 THEN gross_profit ELSE 0 END) DESC) AS gp_rank FROM sales_business_data WHERE year IN (2021, 2022) GROUP BY customer_id, customer_name ) -- 关联你原本的统计查询,筛选Top5客户的所有记录 SELECT stat.customer_id, stat.customer_name, stat.year, stat.sales_amount, stat.gross_profit -- 这里可以添加你原查询中的其他字段 FROM your_original_stat_query stat INNER JOIN customer_gp_rank cgr ON stat.customer_id = cgr.customer_id WHERE cgr.gp_rank <= 5;
说明
- 用CTE
customer_gp_rank先按客户聚合,确保每个客户只有一条排名记录 - 把你原来的统计查询(替换
your_original_stat_query)和这个CTE关联,就能拿到Top5客户的所有年度统计数据
方法2:嵌套窗口函数直接计算客户级排名
如果你的原查询已经是按customer_id + year聚合好的结果,可以直接用嵌套窗口函数给同一客户统一排名:
WITH ranked_records AS ( SELECT *, -- 先取每个客户2022年的毛利润值,再基于这个值给客户排名 DENSE_RANK() OVER( ORDER BY MAX(CASE WHEN year = 2022 THEN gross_profit ELSE 0 END) OVER(PARTITION BY customer_id) DESC ) AS gp_rank FROM your_original_stat_query ) SELECT * FROM ranked_records WHERE gp_rank <= 5;
说明
- 内层窗口函数
MAX(...) OVER(PARTITION BY customer_id)会为同一客户的所有记录返回其2022年的毛利润值 - 外层
DENSE_RANK()基于这个客户级别的值排名,确保同一客户的所有记录排名一致 - 最后筛选排名≤5的记录即可
关键提醒
- 无论用哪种方法,必须保证排名是基于客户整体的2022年毛利润,而不是单条记录的毛利润,否则同一客户会出现多个排名
- 如果你的原数据是订单级的细粒度数据,优先用方法1,先聚合客户维度的指标再排名
内容的提问来源于stack exchange,提问作者Vigna Hari Karthik
相关产品推荐
相关产品推荐

