哦,這太詭異了。我現在有一個幾乎相同的任務 - 除了我的每月從SQL導入到Excel的航班日誌,必須將每日的時間轉移到飛行員的個人工作表。將「賬戶」切換爲「試點」和「金額」爲「飛行時間」,我們的項目完全相同。
我幾乎只是剪下和粘貼下面的代碼,它會爲你做整個shabang。在StackOverflow上解決某個人的整個任務並不是很好的形式,但在這種情況下,只是粘貼一些程序似乎毫無意義。
對我來說,最大的教訓就是把Excel當作數據檢索和數據顯示界面。訣竅是創建自己的數據結構,將數據讀入它們,根據需要操作/詢問它們,然後在完成所有工作時將結果寫入工作表。換句話說,避免像鼠疫這樣的宏觀生成器!我寧願懷疑你的拷貝單元格x,y粘貼到單元格r,c的方法會把你帶到我上升的同樣的死角。我發現的最好的方法是有一個Dictionary
飛行員(帳戶爲你),然後內部Dictionary
的航班日期(價值/日期爲你)。然後,您只需測試一天賬單中每個賬戶的賬戶密鑰和日期密鑰。
要訪問Dictionary
對象,您需要引用Microsoft Scripting Runtime
(工具 - >引用... - >通過勾選複選框在列表中進行選擇)。
您需要創建兩個類 - 這些是您的數據字段。調用第一cAccountFields
和下面的代碼添加到類:
Public AccountName As String
Public ActivityByDate As Dictionary
Public Sub Create(accName As String)
Me.AccountName = accName
Set Me.ActivityByDate = New Dictionary
End Sub
呼叫第二cActivityFields
和下面的代碼添加到類:
Public DateOf As Date
Public Value As Double
Public Sub Create(dat As Date, val As Double)
Me.DateOf = dat
Me.Value = val
End Sub
然後,只需將下面的代碼添加到您的模塊。私有常量需要在模塊級別(即頁面頂部)聲明。您可以使用這些來定義你的行和列的引用 - 它,如果他們匹配了飛行員的日誌,真的是不可思議的:
Private Const DB_SHEET As String = "Sheet1"
Private Const DB_DATE_COL As String = "B"
Private Const DB_ACCOUNT_COL As String = "C"
Private Const DB_VALUE_COL As String = "G"
Private Const DB_ACCOUNT_START_ROW As Long = 1
Private Const DAY_DATE_ADDRESS As String = "A1"
Private Const DAY_ACCOUNT_COL As String = "A"
Private Const DAY_VALUE_COL As String = "B"
Private Const DAY_ACCOUNT_START_ROW As Long = 2
Public Sub ProcessData()
Dim daySheets As Collection
Dim accountsFromDB As Dictionary
Dim account As cAccountFields
Dim activity As cActivityFields
Dim ws As Worksheet
Dim dat As Date
Dim accName As String
Dim accValue As Double
Dim endRow As Long
Dim r As Long
' Create a Collection of the Day sheets
Set daySheets = New Collection
For Each ws In ThisWorkbook.Worksheets
If Left(ws.Name, 4) = "Day " Then
daySheets.Add ws
End If
Next
' Read the database sheet
Set ws = ThisWorkbook.Worksheets(DB_SHEET)
Set accountsFromDB = New Dictionary
endRow = ws.Cells.Find(What:="*", _
After:=ws.Range("A1"), _
LookIn:=xlFormulas, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious).Row
For r = DB_ACCOUNT_START_ROW To endRow
dat = ws.Cells(r, DB_DATE_COL).Value2
accName = ws.Cells(r, DB_ACCOUNT_COL).Text
accValue = ws.Cells(r, DB_VALUE_COL).Value2
' Add the account or retrieve it if it already exists.
If Not accountsFromDB.Exists(accName) Then
Set account = New cAccountFields
account.Create accName
accountsFromDB.Add key:=accName, Item:=account
Else
Set account = accountsFromDB.Item(accName)
End If
' Add the value for a specific date.
If Not account.ActivityByDate.Exists(dat) Then
Set activity = New cActivityFields
activity.Create dat, accValue
account.ActivityByDate.Add key:=dat, Item:=activity
Else
' If the same account and date occurs, then aggregate the values.
Set activity = account.ActivityByDate(dat)
activity.Value = activity.Value + accValue
End If
Next
' Populate the Day sheets
For Each ws In daySheets
dat = ws.Range(DAY_DATE_ADDRESS).Value2
endRow = ws.Cells.Find(What:="*", _
After:=ws.Range("A1"), _
LookIn:=xlFormulas, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious).Row
For r = DAY_ACCOUNT_START_ROW To endRow
accName = ws.Cells(r, DAY_ACCOUNT_COL).Text
' If account and value for this date exists then write the value
If accountsFromDB.Exists(accName) Then
Set account = accountsFromDB.Item(accName)
If account.ActivityByDate.Exists(dat) Then
Set activity = account.ActivityByDate.Item(dat)
ws.Cells(r, DAY_VALUE_COL).Value = activity.Value
End If
End If
Next
Next
End Sub
後的OP Q的更新:在模塊級
添加額外的常量和適當的修改:
Private Const DB_BOOK As String = "Macro Test File.xlsx"
Private Const DAY_BOOK As String = "Macro Test File.xlsx"
Private Const INITIAL_SHEET As String = "Initial Revenue"
Private Const INITIAL_COL As String = "E"
然後使用此代碼:
Dim daySheets As Collection
Dim accountsFromDB As Dictionary
Dim account As cAccountFields
Dim activity As cActivityFields
Dim dbWb As Workbook
Dim dayWb As Workbook
Dim ws As Worksheet
Dim dat As Date
Dim accName As String
Dim accValue As Double
Dim endRow As Long
Dim r As Long
' Assign the workbook containing the database sheet
On Error Resume Next
Set dbWb = Workbooks(DB_BOOK)
On Error GoTo 0
If dbWb Is Nothing Then
MsgBox "Please open " & DB_BOOK & " in this application and run this routine again."
End
End If
' Assign the workbook containing the days sheets
On Error Resume Next
Set dayWb = Workbooks(DAY_BOOK)
On Error GoTo 0
If dayWb Is Nothing Then
MsgBox "Please open " & DAY_BOOK & " in this application and run this routine again."
End
End If
' Create a Collection of the Day sheets
Set daySheets = New Collection
For Each ws In dayWb.Worksheets
If Left(ws.Name, 4) = "Day " Then
daySheets.Add ws
End If
Next
' Read the database sheet
Set ws = dbWb.Worksheets(DB_SHEET)
Set accountsFromDB = New Dictionary
endRow = ws.Cells.Find(What:="*", _
After:=ws.Range("A1"), _
LookIn:=xlFormulas, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious).Row
For r = DB_ACCOUNT_START_ROW To endRow
dat = ws.Cells(r, DB_DATE_COL).Value2
accName = ws.Cells(r, DB_ACCOUNT_COL).Text
accValue = ws.Cells(r, DB_VALUE_COL).Value2
' Add the account or retrieve it if it already exists.
If Not accountsFromDB.Exists(accName) Then
Set account = New cAccountFields
account.Create accName
accountsFromDB.Add Key:=accName, Item:=account
Else
Set account = accountsFromDB.Item(accName)
End If
' Add the value for a specific date.
If Not account.ActivityByDate.Exists(dat) Then
Set activity = New cActivityFields
activity.Create dat, accValue
account.ActivityByDate.Add Key:=dat, Item:=activity
Else
' If the same account and date occurs, then aggregate the values.
Set activity = account.ActivityByDate(dat)
activity.Value = activity.Value + accValue
End If
Next
' Populate the Day sheets
For Each ws In daySheets
dat = ws.Range(DAY_DATE_ADDRESS).Value2
endRow = ws.Cells.Find(What:="*", _
After:=ws.Range("A1"), _
LookIn:=xlFormulas, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious).Row
For r = DAY_ACCOUNT_START_ROW To endRow
' Write the standard formula into the cell
ws.Cells(r, DAY_VALUE_COL).Formula = "='" & INITIAL_SHEET & "'!" & _
INITIAL_COL & CStr(r)
accName = ws.Cells(r, DAY_ACCOUNT_COL).Text
' If account and value for this date exists then write the value
If accountsFromDB.Exists(accName) Then
Set account = accountsFromDB.Item(accName)
If account.ActivityByDate.Exists(dat) Then
Set activity = account.ActivityByDate.Item(dat)
ws.Cells(r, DAY_VALUE_COL).Formula = ws.Cells(r, DAY_VALUE_COL).Formula & _
" + " & CStr(activity.Value)
End If
End If
Next
Next
也許我誤解了這種情況,但它聽起來很可疑,就像您的目標標籤上的一些VLookup配方可以在沒有VBA的情況下做到這一點。是否有一個特定的原因,你不能使用這些呢? – padawan0007
這可能會做到,但它比這更復雜。我還需要代碼來檢查下一列(C)中的文本,以確定它將在表單中的特定日期對應的單元格。例如,將會有一系列與明天9/18相對應的單元格。一旦確定了該範圍,我將需要代碼來識別C列中的文本,並將其與另一個工作表上的其他文本進行匹配,以確定粘貼該值的位置。 – Tom
我很難想象我們正在努力完成什麼。你能告訴我們更多關於你的數據結構的方式嗎? B列是一組日期,你試圖循環測試它們是否在明天和一週之後?它看起來像你設置'x'等於'ActiveCell',但是之後你會測試'ActiveCell'是否等於'x'。看起來,這將在100%的時間內評估爲真。你能否一步一步地解釋你正在嘗試做什麼? – padawan0007