【发布时间】:2019-06-24 23:06:19
【问题描述】:
我正在为我的组织重新设计一些财务报告,以摆脱第三方软件,并希望使用 VBA 来协助实现自动化。从大学开始就没有写过VBA,所以有点生疏。
我已经让代码工作了,但是它的效率非常低,并且每 30 秒运行大约 1000k 条记录,这对于几十万条记录是不可行的。我已经尝试了几种不同的选项,你们都在不同的线程中发布了这些选项,但一定是遗漏了一些东西。
你能看一下吗?
我看过的大多数线程都通过单个单元格或同一张表引用直接输入来执行查找。这是工作表 A 上的单个列(ATB-Allowance Reserving-Calc),然后在工作表 B 上的表中查找查找(计划全局查找)。
我确实希望它跳过错误,不返回任何内容。
我尝试了填充方法以及复制和粘贴,但我都无法使用公式。他们似乎只是想用原始公式中的值填充。
我认为由于在工作表之间来回跳转而无法正常工作,我在不同的计算中遇到了问题。
我不是一个只会尝试一两次的人,所以这绝对是我的尽头。
Dim GlobalExpPct As Variant
Range("AI2").Select 'Gets historical rates from Plan Global Lookups tab
Do
On Error Resume Next
GlobalExpPct = Application.WorksheetFunction.VLookup(ActiveCell.Offset(0, -24), Sheets("Plan Global Lookups").Range("A:B"), 2, False)
ActiveCell.value = GlobalExpPct
GlobalExpPct = vbNullString
ActiveCell.Offset(1, 0).Select
Loop While ActiveCell.Row < 1000 'have this in place to keep it from looping through all the records
我怀疑处理缓慢是由于每次选择下一个单元格,然后基本上再次调用工作表值和公式。我通常会看到公式返回空值或从填充中的前一个公式中获取相同的值。
提前感谢您的帮助。这是一个很好的资源,因为到目前为止,我已经能够在这个网站上解决 99% 的问题。
编辑
Ahmed 提供的这段代码运行良好,但我还需要一个标准:
如果附加列(“T”帐户基类)是“IP”,那么我们可以按照当前设置从“计划全局查找 A:B”中提取。但是,如果它以其他方式填充,我们将需要从另一列的查找中提取。我们可以在同一张表上复制表,或者仍然使用列 A 作为计划的查找,以最有效的为准。这是目前运行良好的代码:
Sub GetGlobals()
Dim IntervalProcessing60k As Integer
Dim SRow As Long
Dim ERow As Long
Dim Src As Variant
Dim AcctPlan
Dim GlobalExpPct As Variant
Dim AcctPlanRng As Range
Dim Rslt() As Variant
Dim t As Date
Dim GetGlobalTime As Date
Dim ActWs As Worksheet
Dim ATBAllowResCalc As Worksheet
Set ActWs = ThisWorkbook.ActiveSheet
Set PlanGlobalWs = ThisWorkbook.Sheets("Plan Global Lookups")
Set ATBAllowResCalc = ThisWorkbook.Sheets("ATB-Allowance Reserving-Calc")
Set AcctGlobalRng = PlanGlobalWs.Range("A1:B" & PlanGlobalWs.Cells(PlanGlobalWs.Rows.Count, 1).End(xlUp).Row)
t = Now()
LastRow = Range("A" & Rows.Count).End(xlUp).Row
IntervalProcessing60k = 0
SRow = 2
ERow = LastRow
Src = ActWs.Range("K" & SRow & ":K" & ERow).value
X = 1
For Rw = SRow To ERow
AcctPlan = Src(Rw - SRow + 1, 1)
On Error Resume Next
GlobalExpPct = Application.WorksheetFunction.VLookup(AcctPlan, AcctGlobalRng, 2, False)
On Error GoTo 0
ReDim Preserve Rslt(1 To X)
Rslt(X) = IIf(IsNull(GlobalExpPct), "", GlobalExpPct)
GlobalExpPct = vbNullString
If Rw > 120000 Then Debug.Print Rw, X, Src(Rw - SRow + 1, 1), Rslt(X)
If X = 60000 Then
ActWs.Range("AI" & IntervalProcessing60k * 60000 + SRow).Resize(UBound(Rslt, 1), 1).value = Application.Transpose(Rslt)
IntervalProcessing60k = IntervalProcessing60k + 1
X = 1
ReDim Rslt(1 To 1)
Else
X = X + 1
End If
Next Rw
ActWs.Range("AI" & IntervalProcessing60k * 60000 + SRow).Resize(UBound(Rslt, 1), 1).value = Application.Transpose(Rslt)
GetGlobalTime = Format(Now() - t, "hh:mm:ss")
End Sub
【问题讨论】:
-
我自己有点生疏,但我会尝试 (1) 使用显式单元格引用,例如 cell(i, j) 而不是 Activecell。 (2) 设置一个单元格,将其复制并粘贴到包含所有需要包含公式的单元格的范围内。
-
您好,欢迎来到 StackOverflow。 “所以”请参阅帮助部分,因为这将指导您在社区中从我们那里获得更多支持。 stackoverflow.com/help 祝你努力!干杯!
-
您可以做几件事来帮助解决这个问题。我认为您将通过使用 Excel 的 Power Query 获得最佳结果。将数据加载到表中,将其添加到 Power Query,然后将两个表合并在一起。
-
查找如何找到范围的最后一行。然后查找
ForNext循环...另外,您的 vlookup 和选择无疑是这里的问题...您可以尝试Find代替并学习如何删除.select -
@Jay Nelson,感谢您的联系。我等待反馈和/或接受答案(至少要保持 SO 精神),同时将 120 K 的时间进一步减少到 8-9 奇数秒. 现在关于最新编辑中的目标,我很困惑如果 col B 中的查找值是空白的,那么我们需要从 Col T (或 IP )中提取值还是只是从 Col T 中提取值(或知识产权)。请说清楚。很高兴找到解决方案(如果按照我的理解,这可能很容易)。等待反馈。快乐的计算。