項目須要,原來的系統不少的統計分析,被要求把數據庫從oracle轉爲mysql,這是很坑的,mysql的統計分析比較弱,不少oracle有的函數,mysql沒有,須要千方百計改造或者編寫函數實現。java
在修改的過程當中,不少小的問題點都解決了,就剩下一個sum over的實現。sum over用來作統計總數很好用,免得再寫一遍或者嵌套一層。mysql
因爲代碼中的不少求總和的字段輸出的行數很少,最後考慮直接用java的反射機制來簡單實現oracle中sum over統計。代碼沒考慮太多通用性,只是根據本身的需求編寫的,實現以下:sql
package xx.xx.xx.utils; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import xx.xx.xx.stat.vmodel.FlowSortData; public class O2mUtils { private static final Logger logger = Logger.getLogger(Thread .currentThread().getStackTrace()[1].getClassName()); private static String format = "%.0f"; /** * 設置保留2位小數,每次使用前調用,用完恢復 */ public static void setFormat() { format = "%.2f"; } private static void resetFormat() { format = "%.0f"; } /** * 獲取get方法、set方法 * @param o 獲取的類對象 * @param fieldFrom get字段名 * @param FieldTo set字段名 * @return */ private static Method[] getMethod(Object o, String ...strings) { int length = strings.length; Method[] methods = new Method[length]; try { Class<?> clazz = o.getClass(); Field fields[] = clazz.getDeclaredFields(); for(Field f : fields) { if(f.getName().equals(strings[0])) { String fieldName = f.getName().substring(0, 1).toUpperCase() + f.getName().substring(1); methods[0] = clazz.getMethod("get" + fieldName); } if(f.getName().equals(strings[1])) { String fieldName = f.getName().substring(0, 1).toUpperCase() + f.getName().substring(1); Class<?> paramType = f.getType(); methods[1] = clazz.getMethod("set" + fieldName, paramType); } if(length == 3 && f.getName().equals(strings[2])) {// 獲取get方法 String fieldName = f.getName().substring(0, 1).toUpperCase() + f.getName().substring(1); methods[2] = clazz.getMethod("get" + fieldName); } } } catch (Exception e) { logger.error("反射獲取方法異常", e); } return methods; } /** * oracle的sum over() 累加實現 * @param list 設置列表 * @param fieldFrom 累加字段 * @param fieldTo 累加和字段 */ public static void sum_over(List<?> list, String fieldFrom, String fieldTo) { Method[] getField = getMethod(list.get(0), fieldFrom, fieldTo); if(getField != null && getField.length == 2) { try { Double total = 0.0; int i = 0; for(; i < list.size(); i++) { Double value = Double.valueOf(getField[0].invoke(list.get(i)).toString()); total += value; } for(Object o : list) { getField[1].invoke(o, new Object[]{String.format(format, total)}); } } catch (Exception e) { logger.error("取值、賦值異常", e); } } resetFormat(); } /** * oracle的sum over(order by) 累加實現 * @param list 設置列表 * @param fieldFrom 累加字段 * @param fieldTo 累加和字段 * @param reverse 正序反序 */ public static void sum_over_order(List<?> list, String fieldFrom, String fieldTo, boolean reverse) { Method[] getField = getMethod(list.get(0), fieldFrom, fieldTo); if(getField != null && getField.length == 2) { try { int size = list.size(); Double[] total = new Double[size]; int i = 0, j = 0; for(; i < size; i++) { total[i] = 0.0; } if(reverse){ for(i = 0; i < size; i++) { for(j = i; j < size; j++) { Double value = Double.valueOf(getField[0].invoke(list.get(i)).toString()); total[j] += value; } } }else { for(i = size -1; i >= 0; i--) { for(j = i; j >= 0; j--) { Double value = Double.valueOf(getField[0].invoke(list.get(i)).toString()); total[j] += value; } } } for(i = 0; i < size; i++) { getField[1].invoke(list.get(i), new Object[]{String.format(format, total[i])}); } } catch (Exception e) { logger.error("取值、賦值異常", e); } } resetFormat(); } /** * oracle的sum over(partition by) 累加實現 * @param list 設置列表 * @param fieldPartition partition by 字段 * @param fieldFrom 累加字段 * @param fieldTo 累加和字段 */ public static void sum_over_partition(List<?> list, String fieldPartition, String fieldFrom, String fieldTo) { Method[] getField = getMethod(list.get(0), fieldFrom, fieldTo, fieldPartition); if(getField != null && getField.length == 3) { try { int size = list.size(); int i = 0, j = 0, strPos = 0; Double total = 0.0; String key = null; for(; i < size; i++) { if(key == null) { key = getField[2].invoke(list.get(i)).toString(); } if(!getField[2].invoke(list.get(i)).toString().equals(key)) { // 遇到下一個累加 for(j = strPos; j < i; j++) { getField[1].invoke(list.get(j), new Object[]{String.format(format, total)}); } key = getField[2].invoke(list.get(i)).toString(); total = 0.0; strPos = i; } Double value = Double.valueOf(getField[0].invoke(list.get(i)).toString()); total += value; } for(j = strPos; j < i; j++) { getField[1].invoke(list.get(j), new Object[]{String.format(format, total)}); } } catch (Exception e) { logger.error("取值、賦值異常", e); } } resetFormat(); } public static void main(String[] args) { List<FlowSortData> list = new ArrayList<FlowSortData>(); int i = 0; for(i = 0; i < 5; i++) { FlowSortData d = new FlowSortData(); d.setNettype("1111"); d.setFlow("100"); list.add(d); } for(i = 0; i < 5; i++) { FlowSortData d = new FlowSortData(); d.setNettype("2222"); d.setFlow("150"); list.add(d); } for(i = 0; i < 5; i++) { FlowSortData d = new FlowSortData(); d.setNettype("3333"); d.setFlow("50"); list.add(d); } // O2mUtils.sum_over(list, "flow", "totalflow"); // O2mUtils.sum_over_order(list, "flow", "totalflow", false); O2mUtils.setFormat(); O2mUtils.sum_over_partition(list, "nettype", "flow", "totalflow"); for(FlowSortData o : list) { System.out.println(o.getNettype() + " , " + o.getFlow() + " , " +o.getTotalflow()); } } }
package xx.xx.xx.stat.vmodel; public class FlowSortData { private String nettype; private String flow; private String totalflow; public String getNettype() { return nettype; } public void setNettype(String nettype) { this.nettype = nettype; } public String getFlow() { return flow; } public void setFlow(String flow) { this.flow = flow; } public String getTotalflow() { return totalflow; } public void setTotalflow(String totalflow) { this.totalflow = totalflow; } }
那時候用的是jdk1.6,如今能夠考慮用java 8的stream來實現。數據庫