现在Oracle有两张表排班表、历史记录表 。
现有查询业务如下:
根据传递的班次和时间区域,得到该班次在此时间区域内生产的产品数量。
TIPS:
3.1 班次 : A / B / C / ALL 其中ALL代表查询所有数量,不区分班次
3.2 时间区域: startTime / endTime (YYYYMMDD HH24MISSFF3)
{
"code": 1,
"data": [
{
"PACKAGE": "p1",
"QTY": 10
},
{
"PACKAGE": "P2",
"QTY": 20
}
],
"message": "成功"
}
Name | Type | COMMONTS |
ID | NUMBER | |
SHIFT1 | VARCHAR2(2) | 白班 |
SHIFT2 | VARCHAR2(2) |
夜班 |
SHIFT3 | VARCHAR2(2) |
|
SYS_DATE | DATE |
Name | Type | COMMONTS |
ID | NUMBER | |
PACKAGE | VARCHAR2(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 calendars;
List hiss;
// 查询出来的包装
List 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 getPacakges(List hiss){
List 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语句完成计算、分组
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));
}
}
@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
在上面的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 : 未完成。