VBA Excel大数据操作永远占用

时间:2011-05-26 05:16:59

标签: arrays vba memory excel-vba excel

我有两个excel文件。

第一个excel文件包含Person Name和Total Days Present列 实施例

PersonName       TotalDays
xyz               
abcd             

另一个excel文件包含人名,日期和状态(存在/不存在)。

PersonName      Date      Status
xyz           1/1/2011    Present
xyz           1/1/2011    Present

我需要将类似的日期状态分组为一个,并将它们计算在第一个excel文件中进行更新。

我在第一个文件中有大约100行,其中第二个文件中有20,000行,我需要检查。因此,为了加快速度,我将第二个文件中的所有行加载到一个数组中并读取它们以计算每个条目是否正常工作。

问题是,在Windows中占用大量内存所以很多应用程序会自动打开并且系统几乎挂起。

在没有内存问题和快速处理的情况下,是否有任何替代方法可以实现我遇到了Scripting.Dictionary,但不确定它是否需要更少的内存。

修改 我尝试使用redim保留和20,000个大小的静态数组,在这两种情况下都会出现同样的问题。

修改

lblStatus.Caption = "Loading to memory"
 Dim ArrAuditData() As AData
 Dim TotalLookUpCount As Integer
 For J = 1 To 50000

 If lookUpRange.Cells(J, cmbChoice.ListIndex) = "Fail" Then
  ReDim Preserve ArrAuditData(J) As AData
    ArrAuditData(TotalLookUpCount).AuditType = lookUpRange.Cells(J, cmdAudit2.ListIndex)
    ArrAuditData(TotalLookUpCount).TransTime = lookUpRange.Cells(J, cmbChoice.ListIndex - 1)
    ArrAuditData(TotalLookUpCount).AuditValue = lookUpRange.Cells(J, cmbChoice.ListIndex)
    ArrAuditData(TotalLookUpCount).Slno = lookUpRange.Cells(J, 0)

    TotalLookUpCount = TotalLookUpCount + 1
ElseIf lookUpRange.Cells(J, cmbChoice.ListIndex) = "" And J > 4 Then Exit For

    End If
    DoEvents
  Next

2 个答案:

答案 0 :(得分:5)

包含4个变体的20,000个元素的数组每个将占用不到2 MB的RAM。我不认为记忆与你的问题有任何关系 - 除非你碰巧使用的是具有2 MB RAM或类似东西的旧计算机。

您的代码如此繁重的一个更可能的原因是您正在循环遍历单元格。 VBA和Excel工作表数据之间的每次通信都会产生很大的开销,当您一次引用一个单元格时,这会增加。在您的情况下,您的循环最多可以执行200,000个单独的单元格引用。

相反,您应该将所有数据一次加载到Variant数组中,然后遍历该数组,如下所示。这明显更快(即使这使用更多内存,而不是更少;但同样,我不认为内存是你的问题)。

lblStatus.Caption = "Loading to memory"
Dim ArrAuditData() As AData
Dim varTemp As Variant
Dim TotalLookUpCount As Integer

' Load everything into a Variant array. 
varTemp = lookUpRange

ReDim ArrAuditData(1 To UBound(varTemp, 1)) As AData

For J = 1 To UBound(varTemp, 1)

    If varTemp(J, cmbChoice.ListIndex) = "Fail" Then

        ArrAuditData(TotalLookUpCount).AuditType = varTemp(J, cmdAudit2.ListIndex)
        ArrAuditData(TotalLookUpCount).TransTime = varTemp(J, cmbChoice.ListIndex - 1)
        ArrAuditData(TotalLookUpCount).AuditValue = varTemp(J, cmbChoice.ListIndex)
        ArrAuditData(TotalLookUpCount).Slno = varTemp(J, 0)
        TotalLookUpCount = TotalLookUpCount + 1

    ElseIf varTemp(J, cmbChoice.ListIndex) = "" And J > 4 Then
        Exit For

    End If

    DoEvents
Next

ReDim Preserve ArrAuditData(TotalLookUpCount) As AData

如需进一步阅读,请查看这篇旧的但仍然相关的文章:http://www.avdf.com/apr98/art_ot003.html

如果您仍然认为RAM是问题,那么请向我们展示AData类型声明。

编辑:此外,永远不要{@ 1}}在这样的循环中! ReDim Preserve是一项非常昂贵的操作,很少需要在任何给定的数组上进行多次操作。这样做20,000次会降低你的代码速度。在这里,我将它从循环中取出,并在最后使用它一次以修剪掉未使用的元素。 (注意我最初ReDim Preserve如何编辑数组以适应最大可能的元素数。)

答案 1 :(得分:3)

我建议采用不同的方法。

如果我正确地解释了这个问题:

  • 你想得到每个人“出席”或“缺席”的天数
  • 第一个文件(称之为file1)每人包含一行(约100人)
  • 第二个文件(称之为文件2)每人每天包含一行(100人和200天= 20000行)
  • 所需的输出是文件1中的两个额外列,是“存在”的计数和“缺席”的计数

我将使用的方法是使用COUNTIF(或者如果你使用Excel 2007或更高版本的COUNTIFS)

假设

  • file1在Sheet1上包含一个名为StatusReport的表,列A =名称,B =存在,C =缺席
  • 每个唯一名称一行
  • file2包含Sheet1上的一个名为StatusData的表,列A =名称,B =日期,C =状态
  • 每个日期的每个名称一行

Excel 2007或2010的解决方案

  • file1单元格B2
    =COUNTIFS(file2.xlsx!StatusData[Name],[Name],file2.xlsx!StatusData[Status],StatusReport[[#Headers],[Present]])
  • file1 cell C2
    =COUNTIFS(file2.xlsx!StatusData[Name],[Name],file2.xlsx!StatusData[Status],StatusReport[[#Headers],[Absent]])

Excel 2003解决方案

  • 在file2 StatusData表中添加一个额外的列D(称之为代码)
    =Sheet1!$A2&"_"&Sheet1!$C2

  • file1单元格B2
    =COUNTIF([file2.xls]Sheet1!$D:$D,Sheet2!$A2&"_"&Sheet2!$B$1)

  • file1 cell C2
    =COUNTIF([file2.xls]Sheet1!$D:$D,Sheet2!$A2&"_"&Sheet2!$C$1)

注意:虽然这些公式给出了相同的结果,但是COUNTIFS + Table在2010年引用了版本,如果快得多,那就不好笑了(我在几秒钟内测试了大约300,000行的更新)。