(本文档仅供参考)
问题
通过电子表格做清单报表,报表数据超10000条,同时在报表中有sum()函数。导出报表在excel中打开发现sum()函数中只sum了前10000条记录,10000条后面的数据为计算。
方案
问题原因:清单报表考虑性能问题,导出是分批导出的,每次导出10000条,因此导出后无法通过sum去计算全部数据。
方案一(适用相关报表数量不多情况):
若清单报表需要使用sum函数计算,建议可以使用excel公式OFFSET,从而规避此问题,参考文档:清单报表使用sum函数,导出只计算前1w行数据
方案二(适用相关报表数量较多,而不想每一个报表手动添加OFFSET公式):
可通过新建宏资源包中的服务端宏并应用于多个电子表格规避,关于创建宏资源包创建可参考文档:https://history.wiki.smartbi.com.cn/pages/viewpage.action?pageId=44499961
类型 | 对象 | 事件 |
---|---|---|
ServerSide | spreadsheetReport | onBeforeOutput |
var Pattern = Packages.java.util.regex.Pattern; var Matcher = Packages.java.util.regex.Matcher; var StringBuffer = Packages.java.lang.StringBuffer; var StringBuilder = Packages.java.lang.StringBuilder; var Integer = Packages.java.lang.Integer; var JSONObject = Packages.smartbi.net.sf.json.JSONObject; /** * 只支持单个sum公式,同时sum公式的内容为单元格位置,不能存在其它运算 * eg:=SUM(A11) or SUM($A11) */ function main(spreadsheetReport) { spreadsheetReport.cacheable = false; var type = spreadsheetReport.outputType; // only the first executeReport need change the formula var operation = spreadsheetReport.operation; var sheetListPages = JSONObject.fromString(operation); var listPage = sheetListPages.optJSONArray("sheetListPages"); if (type == "LIST_EXCEL" && listPage == null) { var workbook = spreadsheetReport.workbook; var worksheet = workbook.worksheets.get(0); var cells = worksheet.cells; var maxDisplayRange = cells.maxDisplayRange; for (var i = 0; i < maxDisplayRange.rowCount; i++) { for (var j = 0; j < maxDisplayRange.columnCount; j++) { var cell = cells.get(i, j); if (!cell.isFormula()) { continue; } var formula = cell.getFormula(); var index = formula.indexOf("SUM"); if (index < 0) { continue; } var replaceStrList = getReplaceStr(formula, index); var sb = new StringBuilder(formula); while (replaceStrList.length != 0) { var str = replaceStrList.pop(); sb.replace(str[0], str[1], str[2]); } var newFormula = sb.toString(); // logger.info("newFormula " + newFormula); cell.setFormula(newFormula); } } } } function getSumEndPosition(formula, start) { var i = start; var stack = ["("]; while (i < formula.length() && stack.length != 0) { if (formula.charAt(i) == 40) { stack.push(formula.charAt(i)); } else if (formula.charAt(i) == 41) { stack.pop(); } i++; } return i; } function getReplaceStr(formula, start) { var position = []; while (start >= 0) { var end = getSumEndPosition(formula, start + 4); // 获取到sum公式对应内容所在的位置 var sumFormula = formula.substring(start, end); var pattern = Pattern.compile("(\\$*[A-Za-z]+)([0-9]+)"); // 匹配$A11和A11两种形式 var matcher = pattern.matcher(sumFormula); var sb = new StringBuffer(); while (matcher.find()) { var letter = matcher.group(1); var number = Integer.valueOf(matcher.group(2)).intValue(); var str = "OFFSET(" + "\\" + letter + (number + 1) + ", -1, 0)"; matcher.appendReplacement(sb, str); } matcher.appendTail(sb); position.push([start, end, sb.toString()]); start = formula.indexOf("SUM", end); } return position; }
注意事项:此服务端宏不适用于SUM公式里面还嵌套其它函数的情况,只支持SUM公式里面是单元格位置,如:单元格形式为$A11或者A11,不支持$A$11