查询数据时,orderby按照指定的复杂业务规则进行排序

最近有一个需求,需要把数据库查询的内容,按照指定字段进行排序,但这个字段并不是数字。

需求描述:

一个结果集数据来源复杂,需要根据某个列(下面举例为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;
    }

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值