业务场景:按月对每个工地状态进行评分, 满分一百分, 对每个工地评分后, 进行排名, 要求相同分数的工地排名相同
在我不知道DENSE_RANK()这个函数前, 我是对每个工地进行算分,所有工地是一个list , 工地的分数在list的map里。
如:[ { key:“工地1” , score:80 } , { key:“工地2”, score:90} , { key:“工地3”, score:60}]
在这样一个数组中, 对工地按评分排名, 其实就是把List数组按map中的某个属性进行排名。 但是这样有个问题, 就是说,相同分数的工地, 排名依然会有个先后顺序。
使用 DENSE_RANK() 可以在sql步骤就对数据进行排序, 不需要用代码进行排序。
select DZShare.T_Y_SCORE.total_score ,DZShare.T_Y_SCORE.time ,
ISNULL(DZShare.T_Y_SCORE.actual_score , 100) as actual_score , DZShare.T_Y_SBBHDEVICE_SITE.work_site_name ,
DZShare.T_Y_SBBHDEVICE_SITE.country , DZShare.T_Y_SBBHDEVICE_SITE.id as sbbhSiteId ,
-- 这里使用DENSE_RANK()
DENSE_RANK() over (order by actual_score desc ) rank from DZShare.T_Y_SBBHDEVICE_SITE left join DZShare.T_Y_SCORE
on DZShare.T_Y_SBBHDEVICE_SITE.id = DZShare.T_Y_SCORE.sbbhdevice_id
and DZShare.T_Y_SCORE.time = '2021-11-01 00:00:00'
where 1=1
and DZShare.T_Y_SBBHDEVICE_SITE.country in ('临邑县' , '武城县')
and DZShare.T_Y_SBBHDEVICE_SITE.engineering_id in (1,2,3)
order by actual_score desc
使用方式:
select * , DENSE_RANK() over (order by actual_score desc ) rank
from table
order by actual_score desc
over 中的写法和order by 子句保持一致。
排序效果如下:
可以看到, 当分数相同是, 排名rank也相同。
除了DENSE_RANK() , 相似的还有 RANK() 函数, 但 RANK() 是跳跃是排名。
什么是跳跃是排名? 我们把sql中的DENSE_RANK() 替换成 RANK() , 会得到如下结果:
当分值都是100 分的工地排名完成后,(都是第一名),然后从当前不是100分的工地位置开始排名计数。也就是分数是75的工地从46位置开始, 那么就从第46开始接着排名。
以上是使用sql进行排名, 那么使用代码进行排名,就是对List中的Map的某个属性进行排名, 当属性相同时,如何确保排名也相同呢?
1:首先定义一个排序方法,对list进行排序, 让list有序
//降序排序
class MapComparatorDesc implements Comparator<Map<String, Object>> {
@Override
public int compare(Map<String, Object> m1, Map<String, Object> m2) {
Double v1 = Double.valueOf(m1.get("countryNumber").toString());
Double v2 = Double.valueOf(m2.get("countryNumber").toString());
if (v2 != null) {
return v2.compareTo(v1);
}
return 0;
}
}
// 对lsit进行排序
Collections.sort(tyScoreCountryList, new MapComparatorDesc());
然后对有序后的list , 按照map中的属性值, 给每个元素一个排名,具体如下:
// 增加排名字段
Map rankMap = new HashMap();
Integer rank =0;
for(int u=0; u<tyScoreCountryList.size(); u++)
{
String countryNumber = tyScoreCountryList.get(u).get("countryNumber").toString();
if(rankMap.containsKey(countryNumber))
{
tyScoreCountryList.get(u).put("rank" , rank);
}
else {
rank+=1;
tyScoreCountryList.get(u).put("rank" ,rank);
rankMap.put(countryNumber , null);
}
}
这里 countryNumber就是工地分数,在保证list是有序的前提下, 按判断分数在rankMap中存不存在来对List添加排名字段,可以实现对list的排名。