如何用SQL根据积分查询用户排行榜名次?含重复用户及同积分问题
解决profile表排行榜同积分同名次的问题
嘿,我懂你的烦恼!当两个用户积分相同时,用count函数确实会把名次给错开,完全不符合咱们想要的“同积分同排名”效果。咱们换个更靠谱的思路,用窗口函数来搞定,既能精准取到每个用户的最新记录,又能完美处理同积分的排名逻辑,一步到位!
第一步:先筛选每个用户的最新记录
首先得把每个用户最新(对应max(lastupdated))的那条数据捞出来,毕竟用户可能多次存入表中。这里用ROW_NUMBER()窗口函数最省心:
WITH latest_profiles AS ( SELECT Id, profilename, points, lastupdated, -- 按用户ID分组,更新时间倒序排列,最新的那条标记为rn=1 ROW_NUMBER() OVER (PARTITION BY Id ORDER BY lastupdated DESC) AS rn FROM profile ) SELECT Id, profilename, points FROM latest_profiles WHERE rn = 1
这个CTE(公共表表达式)会给每个用户的所有记录按更新时间排序,只保留最新的那一行,这样咱们就拿到了干净的、每个用户唯一的最新积分数据。
第二步:计算同积分同名次的排行榜
接下来就是核心的排名环节了,别再用count硬凑了,RANK()或者DENSE_RANK()窗口函数天生就是干这个的:
RANK():如果有两个第1名,下一个名次会直接跳到第3名(跳过重复的名次)DENSE_RANK():如果有两个第1名,下一个名次是第2名(不跳过名次)
你可以根据自己的需求二选一,完整的SQL代码如下:
WITH latest_profiles AS ( SELECT Id, profilename, points, ROW_NUMBER() OVER (PARTITION BY Id ORDER BY lastupdated DESC) AS rn FROM profile ), ranked_profiles AS ( SELECT profilename, points, -- 按积分倒序排序,相同积分自动分配相同名次 RANK() OVER (ORDER BY points DESC) AS rank_position -- 要是想要不跳过名次的逻辑,就换成下面这句: -- DENSE_RANK() OVER (ORDER BY points DESC) AS rank_position FROM latest_profiles WHERE rn = 1 ) SELECT profilename, points, rank_position FROM ranked_profiles ORDER BY rank_position ASC;
为啥之前的count方法会出问题?
举个简单例子:如果有两个用户都是100分,用count统计“比当前用户积分高的人数+1”的话,理论上能得到第1名,但如果你的SQL逻辑没处理好(比如误加了distinct或者关联条件不对),就会导致第二个100分的用户名次变成第2名。而RANK()这类窗口函数会自动识别相同的积分值,直接给它们分配相同的名次,完全不用手动凑逻辑,靠谱得多。
内容的提问来源于stack exchange,提问作者user3511547
相关产品推荐
相关产品推荐

