个人笔记:Code 转换 SQL

需求

现在Oracle有两张表排班表、历史记录表 。

现有查询业务如下: 

根据传递的班次和时间区域,得到该班次在此时间区域内生产的产品数量。

TIPS:

  1. 白班为08:00 - 20:00  夜班为 20:00 - 次日 08:00
  2. 根据不同的产品类型进行分类计算
  3. 传递的参数

3.1    班次 : A / B / C / ALL 其中ALL代表查询所有数量,不区分班次

3.2    时间区域: startTime / endTime  (YYYYMMDD HH24MISSFF3)

  1. 历史记录中的TIMEKEY代表时间戳  (YYYYMMDD HH24MISSFF3)
  2. 返回结果形如:
{
    "code": 1,
    "data": [
        {
            "PACKAGE": "p1",
            "QTY": 10
        },
        {
            "PACKAGE": "P2",
            "QTY": 20
        }
    ],
    "message": "成功"
}

表结构

排班表

NameTypeCOMMONTS
IDNUMBER 
SHIFT1VARCHAR2(2)白班
SHIFT2

VARCHAR2(2)

夜班
SHIFT3

VARCHAR2(2)

 
SYS_DATEDATE 

历史表

NameTypeCOMMONTS
IDNUMBER 
PACKAGEVARCHAR2(25)产品类型
TIMEKEY

VARCHAR2(25)

生产时间戳
MAIN_QTY

NUMBER

数量

 

代码

老版本

说明:老版本所有逻辑全部写在JAVA代码中, 靠的是拼接SQL, 很明显效率低下,且容易报错,不易维护,不易理解。

/**
     * 查询当班产量: 查询 WIPHIS_LOT 表, 根据 eqpId 、  查询对应的数量, 再加上对应的qty值。
     *
     * @param userId
     * @param startTime 历史createTime 起始时间   YYYYMMDD HH24MISSFF3
     * @param endTime   wipHis createTime 结束时间 YYYYMMDD HH24MISSFF3
     * @param shift     班次 :  A/B/C   ALL 查询所有
     * @return 返回的字段有  :  封装 (package)  、数量
     */
    @Override
    public Result getShiftOutput(String startTime, String endTime, String shift) {
        // 1. 获取班次信息 ,截取yyyy-MM-dd进行查询
        Date start = TimeUtil.strToSqlDate(startTime, TimeUtil.sdfymd);
        Date end = TimeUtil.strToSqlDate(endTime, TimeUtil.sdfymd);
        List<VMesBasCalendarDay> calendars;
        List<WipHisLot> hiss;
        // 查询出来的包装
        List<String> packages;
        if (AllShift.equals(shift)) {
            // 是查询ALL 三个班
            Example hisExample = new Example(WipHisLot.class);
            Example.Criteria hisCriteria = hisExample.createCriteria();
            hisCriteria.andBetween("timekey",startTime,endTime);
            hiss = wipHisLotMapper.selectByExample(hisExample);
            packages = getPacakges(hiss);
        } else {
            // 不是ALL
            calendars = mesBasCalendarDayMapper.findByTimesAndShift(start, end, shift);
            // 1. 如果不是ALL , 查询A/B/C 的各天上班时间找 对应的 lot
            //  1.1 构建查询条件
            StringBuilder wheres = new StringBuilder();
            wheres.append("(");
            for (VMesBasCalendarDay vmbc : calendars) {
                // 视图中sfhit格式为 2020-01-19 00:00:00.0
                // 转换日期格式 为 yyyyMMdd
                String time = TimeUtil.formatChange(TimeUtil.sdfymdS, TimeUtil.sdfymd, vmbc.getSysDate());
                // 白班 闭区间
                // ('20200114 080000000' <= TIMEKEY and TIMEKEY <= '20200115 200000000') or
                if (shift.equals(vmbc.getShift1())) {
                    wheres.append("('").append(time).append(" ").append(ShiftDayEnums.DAY.getStartTime()).append("' <= TIMEKEY and TIMEKEY <= '")
                            .append(time).append(" ").append(ShiftDayEnums.DAY.getEndTime()).append("') or ");
                }
                // 夜班 开区间像两边求值   (('20200112 200000000' < TIMEKEY or TIMEKEY < '20200112 080000000')and SUBSTR(TIMEKEY,1,8) = '20200112') or
                else if (shift.equals(vmbc.getShift2())) {
                    wheres.append("(('").append(time).append(" ").append(ShiftDayEnums.NIGHT.getStartTime()).append("' < TIMEKEY or TIMEKEY < '")
                            .append(time).append(" ").append(ShiftDayEnums.NIGHT.getEndTime()).append("')").append(" and SUBSTR(TIMEKEY,1,8) = ")
                            .append(time).append(") or ");
                }
            }
            // 拼接其余查询条件 , 限制查询的lot历史必须为给定的时间段
            wheres.delete(wheres.length() - 3, wheres.length() - 1);
            // 将前面的sql括起来,再添加其他查询条件
            wheres.append(")");
            wheres.append(" and EVENT_NAME = '"+EventNameEnums.LotTrackOut.getName()+"'").append(" and TIMEKEY between '").append(startTime).append("' and '").append(endTime).append("'");
            // 1.2 查询   TIMEKEY
            hiss = wipHisLotMapper.findByWhere(wheres.toString());
            // 1.3 查询封装种类
            wheres.append(" group by PACKAGE");
            packages = wipHisLotMapper.findPackageByWhere(wheres.toString());
        }
        // 2. 计算对应的数量
        JSONArray array = new JSONArray();
        for (String pa : packages) {
            // package字段可能为null。
            if (pa == null){
                continue;
            }
            JSONObject json = new JSONObject();
            int lotNum = 0;
            int qtySum = 0;
            for (WipHisLot wiphis : hiss) {
                // 对应的封装
                if (pa.equals(wiphis.getPackage1())) {
                    lotNum = lotNum + 1;
                    if (wiphis.getDieQty() != null) {
                        qtySum += Integer.valueOf(wiphis.getDieQty());
                    }
                }
            }
            // 3. 封装数据
            json.put("package", pa);
            json.put("qty", qtySum);
            array.add(json);
        }
        return ResultUtil.success(array);
    }



 public List<String> getPacakges(List<WipHisLot> hiss){
        List<String> res = new ArrayList<>();
        for (WipHisLot wipHisLot : hiss){
            res.add(wipHisLot.getPackage1());
        }
        HashSet set = new HashSet<>(res);
        // 清空list
        res.clear();
        res.addAll(set);
        return res;
    }

新版本

省略几乎所有代码,使用SQL语句完成计算、分组

code:

public Result getShiftOutputV2(String userId, String eqpId, String startTime, String endTime, String shift) {
        // 查询出来的包装
        if (AllShift.equals(shift)) {
            // 是查询ALL 三个班
            return  ResultUtil.success(wipHisLotMapper.getShiftOutputAll(eqpId,EventNameEnums.LotTrackOut.getName(),startTime,endTime));
        } else {
            // 不是ALL
           return ResultUtil.success(wipHisLotMapper.getShiftOutput(shift,eqpId,EventNameEnums.LotTrackOut.getName(),startTime,endTime));
        }
    }

mapper:

 @Select("SELECT package,count(lot_id) lotNum,sum(nvl(main_qty,0)) qty FROM  WIPHIS_LOT T1 \n" +
            "WHERE  T1.TIMEKEY between #{startTime} and #{endTime}\n" +
            "and T1.EQP_ID = #{eqpId} \n" +
            "and T1.EVENT_NAME = #{eventName} \n" +
            "group by package ")
    List<Map<String,Object>> getShiftOutputAll(String eqpId , String eventName ,String startTime,String endTime);



@Select("SELECT package,count(lot_id) lotNum,sum(nvl(main_qty,0)) qty FROM  WIPHIS_LOT T1," +
            " (SELECT CASE WHEN SHIFT1=#{shift} THEN TO_CHAR(SYS_DATE,'YYYYMMDD')||' 080000' ELSE TO_CHAR(SYS_DATE-1,'YYYYMMDD')||' 200000' END STARTTIME," +
            " CASE WHEN SHIFT1=#{shift} THEN TO_CHAR(SYS_DATE,'YYYYMMDD')||' 200000' ELSE TO_CHAR(SYS_DATE,'YYYYMMDD')||' 080000'  END ENDTIME" +
            "   FROM  V_MES_BAS_CALENDAR_DAY T" +
            " WHERE (T.SHIFT1=#{shift} OR T.SHIFT2=#{shift})" +
            " AND  SYS_DATE between TO_DATE(SUBSTR(#{startTime},0,8),'YYYYMMDD') and TO_DATE(SUBSTR(#{endTime},0,8),'YYYYMMDD') )T2" +
            " WHERE  T1.TIMEKEY between #{startTime} and #{endTime}" +
            " and T1.EQP_ID = #{eqpId} " +
            " and T1.EVENT_NAME = #{eventName}" +
            " AND T1.TIMEKEY>T2.STARTTIME AND T1.TIMEKEY<T2.ENDTIME" +
            " group by package")
    List<Map<String,Object>> getShiftOutput(String shift, String eqpId, String eventName, String startTime, String endTime);

SQL解释

在上面的getShiftOutput方法中,查询某班在某天的是什么班的SQL 语句如下

SELECT CASE WHEN SHIFT1='C' THEN TO_CHAR(SYS_DATE,'YYYYMMDD')||' 080000' ELSE TO_CHAR(SYS_DATE-1,'YYYYMMDD')||' 200000' END STARTTIME,
    CASE WHEN SHIFT1='C' THEN TO_CHAR(SYS_DATE,'YYYYMMDD')||' 200000' ELSE TO_CHAR(SYS_DATE,'YYYYMMDD')||' 080000'  END ENDTIME
  FROM  V_MES_BAS_CALENDAR_DAY T
    WHERE (T.SHIFT1='C' OR T.SHIFT2='C')
    AND  SYS_DATE between TO_DATE(SUBSTR('20200320 234126',0,8),'YYYYMMDD') and TO_DATE(SUBSTR('20200330 234126',0,8),'YYYYMMDD') 
)T2

>> 获取排班表中SYS_DATE在查询时间段的数据

>> 当shift1 (白班) 是C的时候,那么开始时间为当天早上 08 点 , 否则,为昨天的晚上 20 点

>> 当shift1 (白班) 是C的时候,那么结束时间为当天晚上 20 点 , 否则,为当天的早上 08 点

 

TODO : 未完成。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值