【问题标题】:Import data from excel and consolidate从excel导入数据并合并
【发布时间】:2015-04-05 21:35:44
【问题描述】:

我正在使用以下代码从 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

【问题讨论】:

    标签: vb.net excel


    【解决方案1】:

    @Plutonix 的回答是个好主意,我完全同意他的 cmets 将 ExcelRows 结构/类字段从字符串更改为适当的数字类型。

    另一种可能性是使用 LINQ 对 ExcelRowList 中的数据进行分组。类似于以下内容

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

    请注意,这不会按原样工作,因为 r.Value 和 r.Quantity 是字符串,因此您不能将它们相乘。因此,您应该更改结构中的字段类型,然后在循环单元格时,将单元格值转换为正确的类型。如果演员阵容失败,您将不得不决定该怎么做。

    Group By on MSDN.

    【讨论】:

      【解决方案2】:

      一种方法是使用 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
      

      不清楚“VALUE”是Unit Price还是Sale Amount,因为所有的单位都是1。我不确定我会一遍又一遍地重复SaleDate等数据,关键是DataTable可以替换 XLRows 结构。

      一个关键是您希望使用正确键入的数据,以便您可以乘法和加法。 XLRow 结构的类型正确 - 一切都是字符串而不是日期、十进制、整数等。

      A.要转换的 XLrow 类

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

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

      dgv.DataSource = dt
      

      使用一行 行代码,DGV 将创建列并显示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 将收集原始 XLS 数据而不是 XLRow 结构。 转换为汇总的数字。接下来使用linq对数据进行汇总;也许进入另一个数据表。示例:

      样本数据:

      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
      

      关键是,一旦您将类型化数据置于有用的结构中,它的作用就很像 SUMIF。结果显示,数据有 5 个 Pepsi 条目,共 7 个单位,7*2 = 14。

      我认为循环版本更容易管理和调试,而且更经济,因为摘要是在读取 XLS 行时动态构建的。

      【讨论】:

      • 谢谢大家,稍后我会看看这些。我真的不需要查看 ListView 或 Data 表中的数据,因为我正在寻找结构化合并格式的输出(这目前适用于我的 listview)。关于读入 OleDB,该文件将始终是 Excel 文件,并且文件顶部有许多截止日期和其他不需要的信息。
      猜你喜欢
      • 2021-01-02
      • 2020-02-24
      • 1970-01-01
      • 2010-11-14
      • 1970-01-01
      • 2016-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多