2011-05-26 77 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