zoukankan      html  css  js  c++  java
  • c# NPOI通过单元格里的公式,计算数值

    业务场景

    公司B是母公司A的子公司,每个月都需要将耗材销售情况统计向总公司报账。

    其中计算的内容如下:

           1、该时间段客户a、b、c 。。。z的分别购买耗材金额,即该客户端销售额

      2、对于a、b、c 。。。z公司,每销售一个单位数量的耗材都有居间费(抽成)

     以上Excel中A-P列是从系统导出来的,其中Q(佣金总额)、P(业绩)列是公式拖拽生成的。

    Q列的公式 H2 * M2(M列如果没有,默认为0)

    R列的公式 L2 - Q2

    以上公式,如果在任何一个Excel中,经过拖拽都很容易实现。

    笔者以下使用C#中NPOI实现,将计算获得的数据存入DataTable

    关键代码DataField.cs

    public class DataField
    {
        private string _label;
        private string _name;
        private Type _type;
        private int _columnWidth = 10 /* default 10 */;
        private string _formula;     
        private bool _isRequireCreateColumn;
     
        public DataField()
        { }
    
        public DataField(string label, string name, Type type)
        {
            this._label = label;
            this._name = name;
            this._type = type;
        }
    
        public DataField(string label, string name, Type type, int columnWidth):this(label,name,type)
        {
            this.ColumnWidth = columnWidth;
        }
    
        public DataField(string label, string name, Type type, string formula)
       : this(label, name, type)
        {
            this._formula = formula;            
        }
    
        
        public DataField(string label, string name, Type type, int columnWidth, string formula) 
            : this(label, name, type,columnWidth)
        {
            this._formula = formula;            
        }
    
    
        public DataField(string label, string name, Type type, string formula, bool isRequireCreateColumn)
            : this(label, name, type,formula)
        {
            this._isRequireCreateColumn = isRequireCreateColumn;
        }
    
        public DataField(string label, string name, Type type, int columnWidth, string formula, bool isRequireCreateColumn)
            : this(label, name, type,formula,isRequireCreateColumn)
        {
            this._columnWidth = columnWidth;
        }
    
    
        /// <summary>
        /// 字段显示名称
        /// </summary>
        public string Label { get => _label; set => _label = value; }
    
        /// <summary>
        /// 字段属性名
        /// </summary>
        public string Name { get => _name; set => _name = value; }
    
        /// <summary>
        /// 字段数据类型
        /// </summary>
        public Type Type { get => _type; set => _type = value; }
    
        /// <summary>
        /// 字段宽度(n *256)
        /// </summary>
        public int ColumnWidth { get => _columnWidth; set => _columnWidth = value; }
    
        /// <summary>
        /// 公式(该字段必须是计算生成的类型)
        /// </summary>
        public string Formula { get => _formula; set => _formula = value; }
       
        /// <summary>
        /// 该字段通过创建插入表格中
        /// </summary>
        public bool IsRequireCreateColumn { get => _isRequireCreateColumn; set => _isRequireCreateColumn = value; }
        
    }

    关键业务代码

    private static DataField[] fields = new DataField[] {
            new DataField("序号","id",typeof(short)),
            new DataField("选择","checked",typeof(string)),
            //delivery time交货时间
            //发货时间 
            new DataField("发货日期","shippingTime",typeof(DateTime)),
            new DataField("客户简称","customerAbbreviation",typeof(string)),
            new DataField("销售部门","department",typeof(string)),
            new DataField("业 务 员","seller",typeof(string)),
            new DataField("存货名称","productName",typeof(string),25),
            new DataField("数量","quantity",typeof(int)),
            new DataField("销售单位","unit",typeof(string)),
            new DataField("无税单价","price",typeof(float)),
            new DataField("无税金额","amount1",typeof(float)),
            new DataField("价税合计","amount2",typeof(float)),
            new DataField("居间费","commission",typeof(float)),
            new DataField("发票总金额","",typeof(string)),
            new DataField("制单人","",typeof(string)),
            new DataField("审核人","",typeof(string)),
            new DataField("佣金总额","totalCommission",typeof(float),"H{0} * M{0}",true),
            new DataField("业绩","performance",typeof(float),"L{0} - Q{0}",true)
        };
    
    
    for (int lineNum = 0; lineNum < rowCount; ++lineNum)
    {
        DataRow NewRow = myTable.NewRow();
        for (int index = 0; index < fields.Length; index++)
        {
            var field = fields[index];
            string formula = field.Formula;
            string label = field.Label;
            string name = field.Name;
            Type type = field.Type;
            bool isRequireCreateColumn = field.IsRequireCreateColumn;
    
            ICell cell;
            object value = null;
            //如果公式的值不为null/空字符等,则认为该列是需要计算生成的
            if (isRequireCreateColumn || !string.IsNullOrWhiteSpace(formula))
            {
                //新建列并设置数据类型为公式
                cell = defaultSheet.GetRow(lineNum + 1).CreateCell(index);            
                cell.SetCellType(CellType.Formula);
                cell.SetCellFormula(string.Format(formula, lineNum + 2));
                //评估表达式的值
                workbook.GetCreationHelper().CreateFormulaEvaluator().EvaluateFormulaCell(cell);
                value = cell.NumericCellValue;
            }
        }
    }

    笔者为每个列额外设置了数据类型(即DataField的Type属性),是为了方便在DataTable及后续里面进行数值计算甚至精确度裁剪。

    经过以上设置,就可以计算出数值了

     最终效果

    其他参考:

    https://stackoverflow.com/questions/24088737/how-to-re-calculate-a-cells-formula

    https://www.cr173.com/html/18143_all.html

    https://www.cnblogs.com/shiyh/p/7478222.html

    https://stackoverflow.com/questions/25077009/npoi-setcellformula-custom-formula-in-vba

    https://stackoverflow.com/questions/17475359/how-to-use-npoi-to-read-excel-spreadsheet-that-contains-empty-cells

  • 相关阅读:
    索引yellow 分片 UNASSIGNED 解决方案1
    Linux zip压缩多文件
    查询数据库实例名,服务名,和oracle_sid
    excel2csv 多sheet拆分到不同csv
    创建按月自动分区表
    自动生成sequence
    oracle 11g 分区表创建(自动按年、月、日分区)
    linux 查找字符串
    Oracle 字符串截取和位置
    mongodb查询某个字段数据
  • 原文地址:https://www.cnblogs.com/passedbylove/p/12234352.html
Copyright © 2011-2022 走看看