页面树结构
转至元数据结尾
转至元数据起始

(本文档仅供参考)

问题

通过电子表格做清单报表,报表数据超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

        


  • 无标签