最近有一个需求,需要把数据库查询的内容,按照指定字段进行排序,但这个字段并不是数字。
需求描述:
一个结果集数据来源复杂,需要根据某个列(下面举例为fieldX)的值不同,对数据进行不同排序,该列包含a、b、c、d、e以及其它任意值,现在要按照a排第一,b排第二、c排第三、d排第四、e排第五,其余任一值排第六的方法进行排序。
首先,sql的order by可以用如下方式根据主键,控制指定行数据排在指定位置,如下方式就实现了id=55的排在第一位 id=42的排在第二位,没有参与case when的就默认排序
select id,fieldX from tabx order by case id when 55 then 1 when 42 then 2 end
借助上面的sql方案,我们只需要维护好期望的id顺序,即可实现该需求。
主要依赖Collectors接口的两个方法实现:
- List.sort();
将List集合,按照List中的对象的指定字段进行排序
- Collectors.groupingBy();
将List集合,根据List中的对象的指定字段将其拆分为多个组,为保持有序,使用了LinkedHashMap
具体代码如下:
private String getOrderBy(String oldSql){
RecordSet rs = new RecordSet();
//自定义排序规则 key=字段值 value=当字段为该值时的优先级
Map<String,Integer> sortRule = new HashMap<>();
sortRule.put("fwsm",1);
sortRule.put("zw",2);
sortRule.put("fj",3);
sortRule.put("glwj",4);
sortRule.put("gllc",5);
sortRule.put("other",6);//其它值
try{
//执行查询sql的伪代码
rs.executeQuery(oldSql);
List<SortRule> list = new ArrayList<>();
//循环一遍要排序的sql,用于维护好每个字段的优先级
while (rs.next()){
//restype : 1=流程 2=文档 3=附件
String restype = rs.getString("restype");
String id = rs.getString("id");
String resname = rs.getString("resname");
String fieldname = rs.getString("fieldname");
SortRule temp = new SortRule();
temp.setId(id);
temp.setResname(resname);
temp.setFieldname(fieldname);
if("3".equals(restype) && "fwsm".equals(fieldname)){
temp.setOrderid(sortRule.get("fwsm"));
}
else if("2".equals(restype) && "zw".equals(fieldname)){
temp.setOrderid(sortRule.get("zw"));
}
else if("3".equals(restype) && "fj".equals(fieldname)){
temp.setOrderid(sortRule.get("fj"));
}
else if("3".equals(restype) && "glwj".equals(fieldname)){
temp.setOrderid(sortRule.get("glwj"));
}
else if("1".equals(restype) && "gllc".equals(fieldname)){
temp.setOrderid(sortRule.get("gllc"));
}
else{//非以上几个字段
temp.setOrderid(sortRule.get("other"));
}
list.add(temp);
}
//第一次排序 按照上面的order进行排序
//lambda表达式缩写 不推荐,没必要为了代码的简洁降低可读性
// list.sort((o1,o2)->(o1.getOrderid() -o2.getOrderid()));
list.sort(new Comparator<SortRule>() {
@Override
public int compare(SortRule o1, SortRule o2) {
return o1.getOrderid() -o2.getOrderid();
}
});
//第二次排序,基于第一次,根据resname排序,第一个字符为数字的,从大到小,没数字的排在最后
//第一步 先按照优先级ordeby分组
LinkedHashMap<Integer, List<SortRule>> groupList= list.stream().collect(
Collectors.groupingBy(SortRule::getOrderid,
LinkedHashMap::new,
Collectors.toList())
);
List<SortRule> newlist = new ArrayList<>();
//遍历每个组 单独按照resname的第一个数字进行排序
for(Map.Entry<Integer, List<SortRule>> entry : groupList.entrySet()){
List<SortRule> temp = entry.getValue();
temp.sort(new Comparator<SortRule>() {
@Override
public int compare(SortRule o1, SortRule o2) {
return getSerialNumber(o1.getResname()) - getSerialNumber(o2.getResname());
}
});
newlist.addAll(temp);
}
String sortIdByCaseWhen = "";
for (int i = 0; i < newlist.size(); i++) {
SortRule temp = newlist.get(i);
int tempid = Util.getIntValue(temp.getId());
sortIdByCaseWhen += " when "+tempid+" then "+(i+1)+" ";//i用于orderby中的排序序号 从1开始即可
}
if(!"".equals(sortIdByCaseWhen)){
String orderby = " case id "+sortIdByCaseWhen+" end ";
return orderby;
}
}catch (Exception e){
return "";
}
return "";
}
/**
* 截取字符串中的序号,支持负数
* @param str
* @return
*/
private int getSerialNumber(String str){
int serialNumber = 0;
int i = 0;
for (; i < str.length(); i++) {
Character t = str.charAt(i);
if(i ==0 && t == '-')//第一个为负数符号 直接跳过
continue;
if(!Character.isDigit(t)){
break;
}
}
if(i > 0){
try{
serialNumber = Integer.parseInt(str.substring(0,i));
}catch (Exception e){
}
}
return serialNumber;
}