2011-05-26 88 views
2

我有两个excel文件。VBA Excel大数据处理永远需要

第一个excel文件包含Person Name和Total Days Present列 Ex。

PersonName  TotalDays 
xyz    
abcd    

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

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

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

我在第一个文件中有大约100行,其中第二个文件需要检查20000行。所以为了让它更快,我将第二个文件中的所有行加载到数组中,并读取它们以计算每个正确工作的条目。

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

是否有任何替代方案来实现这个没有内存问题和快速处理。我遇到了Scripting.Dictionary,但不确定它是否会占用较少的内存。

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

EDIT

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 
+0

你可以在你认为问题发生的地方粘贴一段代码吗?仅凭描述就很难弄清楚你所做的事情。 – jonsca 2011-05-26 05:43:36

+0

另外,你有'Application.ScreenUpdating = False'?这应该可以为您节省一些计算负担。 – jonsca 2011-05-26 05:45:20

+0

@jonsca:真的?屏幕上没有任何内容正在改变。在这种情况下'.ScreenUpdating = False'仍然可以节省计算负担吗? – 2011-05-26 13:26:49

回答

5

含有各4种变体20000个元件的阵列将占用小于2 MB的RAM。我不认为记忆与你的问题有任何关系 - 除非你恰好在使用具有2MB 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类型声明。

编辑:此外,从来没有ReDim Preserve这样的循环内! ReDim Preserve是一个非常昂贵的操作,很少需要在任何给定的阵列上多次执行。做2万次会减慢你的代码。在这里,我将它从循环中取出,并在最后使用它来修剪未使用的元素。 (请注意我最初的ReDim是如何编辑这个数组以适应最大可能数目的元素。)

+0

我尝试不使用redim preseve,它速度更快,但内存问题相同。如果我为每个条目读取每个单元格,而不是使用数组,则不会出现内存问题,但需要10-15分钟左右的时间。这里是Adata结构'代码'Public Type AData Slno As String AuditType As String TransTime As String AuditValue As String End Type – AjayR 2011-05-27 05:43:09

+0

好的,4个String类型的元素。你的琴弦平均多久?你有多少内存?我仍然怀疑内存是否是问题,除非你的字符串长得可笑(或其他应用程序正在耗尽你所有的RAM)。如果字符串长度为1000个字符,那么20,000个元素的数组将只填充80 MB。 – 2011-05-27 07:51:50

+0

不,字符串最多20个字符,RAM是2 GB。当时没有其他程序启动。它在不同的系统中重复着。 – AjayR 2011-05-28 02:18:24

3

我会建议一种不同的方法。

如果我理解正确的问题:

  • 你想要得到的天数每个人“有”或“不存在”
  • 的第一个文件(称为文件1)包含每一个行人(约100人)
  • 第二个文件(称为file2)每人每天包含一行(100人,200天= 20000行)
  • 期望的输出是文件1中的两个额外列, “Present”的计数和“Absent”的计数

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

假设

  • 文件1包含表Sheet1上称为StatusReport,列A =名称,B =现在,C =无
  • 每一行对应一个唯一的名称
  • 文件2包含表Sheet1上称为StatusData,列A =名称,B =日期,C =状态
  • 每一行对应一个名字对于每一日期

解决方案Excel 2007或2010

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

Solu重刑为Excel 2003

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

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

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

注意:虽然这些公式给出了与2010年COUNTIFS + Table引用版本相同的结果,但如果速度太快,它不会很有趣(我的测试在几秒钟内更新大约300,000行)。

+0

感谢@chris,它给了我一些线索并在此工作 – AjayR 2011-05-27 05:22:20