从Excel导入数据并合并

我正在使用下面的代码来读取一个Excel文件,并将某些列添加到列表视图。 一旦导入我然后导出到CSV(代码未显示)。

我的问题是,Excel文件是一个直到提取,它显示数据交易,导致数千行。 我想执行基于EPoS线的SUMIF相当于excel,并巩固信息,如果可能的话?

下面的数据示例…

样本信息

  Public Structure ExcelRows Dim Unit As String Dim Outlet As String Dim EPoS As String Dim Quantity As String Dim Value As String Dim DateSale As String End Structure Public ExcelRowList As List(Of ExcelRows) = New List(Of ExcelRows) Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load End Sub Public Function GetInfo() As Boolean Dim Completed As Boolean = False Dim MyExcel As New Excel.Application Dim enUK As New CultureInfo("en-GB") Dim DOS As String = "01/04/15" MyExcel.Workbooks.Open("C:\Dropbox\Tills\taRunAction1.xlsx") MyExcel.Sheets("Report").Activate() MyExcel.Range("A10").Activate() Dim ThisRow As New ExcelRows Do If MyExcel.ActiveCell.Value > Nothing Or MyExcel.ActiveCell.Text > Nothing Then ThisRow.Unit = MyExcel.ActiveCell.Value MyExcel.ActiveCell.Offset(0, 1).Activate() ThisRow.Outlet = MyExcel.ActiveCell.Value MyExcel.ActiveCell.Offset(0, 1).Activate() ThisRow.DateSale = MyExcel.ActiveCell.Value MyExcel.ActiveCell.Offset(0, 2).Activate() ThisRow.EPoS = MyExcel.ActiveCell.Value MyExcel.ActiveCell.Offset(0, 1).Activate() ThisRow.Quantity = MyExcel.ActiveCell.Value MyExcel.ActiveCell.Offset(0, 1).Activate() ThisRow.Value = MyExcel.ActiveCell.Value ExcelRowList.Add(ThisRow) MyExcel.ActiveCell.Offset(1, -6).Activate() Else Completed = True Exit Do End If Loop MyExcel.Workbooks.Close() MyExcel = Nothing Return Completed End Function Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click If GetInfo() = True Then For Each xItem In ExcelRowList Dim lViewItem As ListViewItem lViewItem = ListView1.Items.Add(xItem.Unit) lViewItem.SubItems.AddRange(New String() {xItem.Outlet, xItem.EPoS, xItem.Quantity, xItem.Value, xItem.DateSale}) Next End If End Sub 

@ Plutonix的答案是一个好主意,我完全同意他的意见,关于将您的ExcelRows结构/类字段从string更改为适当的数字types。

另一种可能是使用LINQ来分组ExcelRowList中的数据。 像下面这样

 Dim results = From r In ExcelRowList Group By r.EPoS Into Group, Sum(r.Value * r.Quantity) 

请注意,这将无法正常工作,因为r.Value和r.Quantity是string,因此您无法将它们相乘。 因此,您应该更改结构中的字段types,然后在循环单元格时将单元格值转换为正确的types。 如果演员失败,你将不得不决定怎么做。

在MSDN上分组 。

一种方法是使用DataTable:

 Private dt As DataTable ... dt = New DataTable dt.Columns.Add("EPOS", GetType(Integer)) dt.Columns.Add("Unit", GetType(String)) dt.Columns.Add("Quantity", GetType(Integer)) dt.Columns.Add("Value", GetType(Decimal)) dt.Columns.Add("Total", GetType(Decimal)) dt.Columns.Add("Date", GetType(DateTime)) Dim keys As DataColumn() = {dt.Columns("EPOS")} dt.PrimaryKey = keys 

目前尚不清楚“价值”是单价还是销售额,因为所有单位都是1.我不确定我是否会反复重复SaleDate等数据,关键是DataTable可以代替 XLRows结构。

一个关键是你想正确使用Typed数据,所以你可以乘法和添加。 XLRow结构没有正确input – 一切都是string,而不是date,小数,整数等

A. XLRow类转换

为此,将XLRow结构转换为一个类。 它的作用是从XL获取string数据并转换为Typed数据。 接下来,DataTable用于收集汇总数据。

为此,上面的PrimaryKey定义是至关重要的。 它会阻止您添加第二个(或第1000个)“百事可乐”项目,并允许您find该总结项目。 也许最重要的是,您可以摆脱ListView并使用DataGridView

 dgv.DataSource = dt 

在这里输入图像描述

通过一行代码,DGV将创build列并显示DataTable中的所有行。 与ListView不同,随着DataTable中的基础数据更改,它将自行更新。 迭代您的数据以在循环内汇总:

 ' get the row for this EPOS code Dim dr As DataRow = dt.Rows.Find(xl.EPOS) If dr IsNot Nothing Then ' we already have this item, increment Quan, TotalSales: dr("Quantity") += xl.Quantity dr("Total") += (xl.Quantity * xl.Value) Else ' new transaction item, add it: dt.Rows.Add(xl.EPOS, xl.Unit, xl.Quantity, xl.Value, (xl.Quantity * xl.Value), xl.DateSale) End If 

这非常简洁,因为在读取XL数据时,它会被添加到摘要中。 在执行汇总之前,不需要将所有详细数据(XLS行)导入到集合或数据表中。


B.使用Linq而不是XLRow结构

为此在DataTable中省略主键 。 在这种情况下,DataTable将收集原始XLS数据而不是XLRow结构。 转换为汇总的数字。 接下来,使用linq来汇总数据; 也许进入另一个DataTable。 例:

样本数据:

 dt.Rows.Add(10001, "Ginger Ale", 1, 2.25, #4/5/2015#) dt.Rows.Add(34582, "Pepsi", 3, 6.0, #4/5/2015#) dt.Rows.Add(10002, "Chips", 1, 3.25, #4/5/2015#) dt.Rows.Add(34582, "Pepsi", 1, 2.0, #4/5/2015#) dt.Rows.Add(78301, "Roast Duck", 1, 15.25, #4/5/2015#) dt.Rows.Add(34582, "Pepsi", 1, 2.0, #4/5/2015#) dt.Rows.Add(34582, "Pepsi", 1, 2.0, #4/5/2015#) dt.Rows.Add(10002, "Chips", 1, 3.25, #4/5/2015#) dt.Rows.Add(34582, "Pepsi", 1, 2.0, #4/5/2015#) 

获取摘要信息:

 ' group the data by EPOS code Dim drs = From row In dt.AsEnumerable() Group row By ID = row.Field(Of Integer)("EPOS") Into Group Select Group Dim TotSales As Decimal Dim TotUnits As Integer ' each DRS is a collection of all the items with the same EPOS code Dim dr As DataRow() Console.WriteLine("EPOS Item Lines Units Total Sales") ' get the total sales in each group For n As Integer = 0 To drs.Count - 1 dr = drs(n) ' the current EPOC group TotUnits = dr.Sum(Function(t) t.Field(Of Integer)("Quantity")) ' Sales could just be TotUnits * dr(0)("Value") ' sample data makes it unclear if Value is the UNITPRICE or SALEAMOUNT ' This assumes it is SALEAMOUNT such that 2 Pepsi = 4.00 TotSales = dr.Sum(Function(t) t.Field(Of Decimal)("Value")) ' ToDo: do something interesting with the totals Console.WriteLine("{0} {1} {2} {3} {4}", dr(0)("EPOS"), dr(0)("Unit").ToString, dr.Length.ToString("D2"), TotUnits.ToString, TotSales.ToString("C2")) Next 

输出:

 EPOS Item Lines Units Total Sales 10001 Ginger Ale 01 1 $2.25 34582 Pepsi 05 7 $14.00 10002 Chips 02 2 $6.50 78301 Roast Duck 01 1 $15.25 

关键在于,一旦将types化的数据放在有用的结构中,它的行为就像SUMIF一样。 结果表明,该数据有5个百事可乐项目,7个总单位,7 * 2 = 14。

我认为循环版本的pipe理和debugging稍微容易一些,而且由于摘要是在读入XLS行的同时构build的,因此更加经济。