"on error goto" 故障。如何处理连续错误并忽略最后一行命令
"on error goto" glitch. How to deal with a consecutive error and ignoring last row command
我刚刚在 vba
学习 abc
我一直在使用这段代码,根据另外 2 个自动填充列表。
我有一个客户列表,每个客户都有一个顾问,我需要填充每个客户所属的团队,并设法使用 VLookUp 应用程序关联顾问-经理-团队。
所以当我们有一位新的顾问加入并且还没有被添加到“顾问-经理”列表中时,
显然,我得到了一个错误。我尝试使用“On Error Resume Next”修复它,但它只是使用最后一个有效的团队名称将错误填充到单元格中并继续。
所以我插入了一个处理程序(见下面的代码),让它将单元格留空并继续前进,当出现一个错误时它工作正常,但当出现 2 个连续错误时:
- 该宏会将第一个单元格留空,但会使用最后一个有效团队名称在第二个单元格中填充错误。
- 即使在列表结束后它也会继续填充,忽略我为循环提供的条件(下面代码中的 NumRows)。
哪位大神能指导一下错误处理流程怎么修改吗?
Sub populateteam()
Dim wbFollowUp As Workbook
Dim wbList As Workbook
Set wbFollowUp = ThisWorkbook
Set wbList = Workbooks.Open("C:\<folders>\CSTeams.xlsx")
Dim wsAkasaka As Worksheet
Dim wsList As Worksheet
Set wsAkasaka = wbFollowUp.Worksheets("Akasaka")
Set wsList = wbList.Worksheets("All Japan")
wbFollowUp.Activate
Dim consultant As String
Dim manager As String
Dim team As String
Dim x As Integer
Application.ScreenUpdating = False
NumRows = Range("b2", Range("b2").End(xlDown)).Rows.Count
For x = 1 To NumRows
consultant = wsAkasaka.Range("b" & (ActiveCell.Row)).Value
On Error GoTo handler:
manager = Application.VLookup(consultant, wsList.Range("a13:c250"), 3, False)
team = Application.VLookup(manager, wsList.Range("e2:F11"), 2, False)
'The name of the manager in the consultant list and in the team list should be exactly the same,
'including spaces before and after
If IsEmpty(ActiveCell.Value) Then
ActiveCell.Value = team
ActiveCell.Offset(1, 0).Select
End If
Next
Application.ScreenUpdating = True
handler:
ActiveCell.Value = ""
ActiveCell.Offset(1, 0).Select
Resume Next
End Sub
您的错误处理未按预期进行。如果您阅读 Resume Statement 的文档,它说 Resume Next
执行以下操作:
Execution resumes with the statement immediately following the statement that caused the error.
因此,如果 manager = Application.VLookup(consultant, wsList.Range("a13:c250"), 3, False)
中出现错误,因为找不到 consultant
。它将继续使用 next 行,即 team = Application.VLookup(manager, wsList.Range("e2:F11"), 2, False)
但由于 manager
未检索到,这再次进入错误处理程序。然后它再次处理 *next 行,即 If IsEmpty(ActiveCell.Value) Then
.
所以实际的问题是你使用了.Select
和ActiveCell
。您可能会从阅读 How to avoid using Select in Excel VBA 中获益。而不是使用 .Select
直接引用您的单元格(参见下面的代码):
Option Explicit
Public populateteam()
Dim wbFollowUp As Workbook
Set wbFollowUp = ThisWorkbook
Dim wbList As Workbook
Set wbList = Workbooks.Open("C:\<folders>\CSTeams.xlsx")
Dim wsAkasaka As Worksheet
Set wsAkasaka = wbFollowUp.Worksheets("Akasaka")
Dim wsList As Worksheet
Set wsList = wbList.Worksheets("All Japan")
Application.ScreenUpdating = False
Dim LastRow As Long
LastRow = wsAkasaka.Range("B2").End(xlDown).Row
Dim iRow As Long
For iRow = 2 To LastRow ' start in row 2 and run to last row if you want to start from the active cells row use `ActiveCell.Row` instead of 2
Dim consultant As String
consultant = wsAkasaka.Cells(iRow, "B").Value
Dim manager As Variant
manager = Application.VLookup(consultant, wsList.Range("A13:C250"), 3, False)
If Not IsError(manager) Then
Dim team As Variant
team = Application.VLookup(manager, wsList.Range("E2:F11"), 2, False)
'The name of the manager in the consultant list and in the team list should be exactly the same,
'including spaces before and after
If Not IsError(team) Then
With wsAkasaka.Cells(iRow, "B") 'replace "B" with the column letter where you want to write your team!
If IsEmpty(.Value) Then
.Value = team
End If
End With
End If
End If
Next iRow
Application.ScreenUpdating = True
End Sub
Note that the "B"
in the With
statement needs to be adjusted to the column where you want to write the team
value!
在您看到的代码中,我完全通过像 wsAkasaka.Cells(iRow, "B").Value
这样的完整单元格引用消除了 ActiveCell
和 .Select
它现在使用循环中的索引 iRow
。
我还删除了错误处理并检查查找是否得出结果(这比错误处理更高效并且更容易完成)。因此,如果查找成功,代码只会继续执行以下步骤。如果发生错误,它会自动处理下一行 Next iRow
.
只是一个旁注。 Excel 的行数超过了 Integer
的处理能力。因此需要声明行计数变量 Long
。由于 VBA 中有 no benefit in using Integer
,我建议始终使用 Long
。
如果您单步执行代码 line-by-line,您可以自己找到这些问题。事实上,只要错误处理没有像您预期的那样工作,您就应该单步执行代码 line-by-line 以确切了解发生了什么。
对于你的第一期,
The macro would leave the first one in blank but populated the second cell with an error using the last valid team name.
想一想当您有新顾问时您的代码 运行s 发生了什么:
- 行
manager = Application.VLookup(consultant, wsList.Range("a13:c250"), 3, False)
会抛出一个错误。请注意,manager
的值 不会 更新,因此将保持之前的值。
- 您的代码通过
handler
块,用“”填充单元格,移动到下一个单元格,然后 Resume Next
行直接将您带到 team = Application.VLookup(manager, wsList.Range("e2:F11"), 2, False)
- 现在,
manager
的值与上次 运行 的值相同,因此 team
的值将与上次 [=53] 的值相同=].
我对你的 If IsEmpty(ActiveCell.Value) Then
循环有点困惑,所以这个建议可能不是你想要完成的,但我建议在你的 [=19] 中添加一个 Else
子句=] 语句,然后将行 team = Application.VLookup(manager, wsList.Range("e2:F11"), 2, False)
移动到该 Else
子句下。当使用现有的 consultant
.
更新 manager
值时,这只会将 team
写入单元格
关于你的第二期,
It keeps populating even after the list ended, ignoring the condition I gave it for the loop (NumRows in code below).
你检查过NumRows
的值了吗?这一行Range("b2", Range("b2").End(xlDown)).Rows.Count
的价值比你想象的要大得多:超过100万
我刚刚在 vba
学习 abc我一直在使用这段代码,根据另外 2 个自动填充列表。 我有一个客户列表,每个客户都有一个顾问,我需要填充每个客户所属的团队,并设法使用 VLookUp 应用程序关联顾问-经理-团队。
所以当我们有一位新的顾问加入并且还没有被添加到“顾问-经理”列表中时, 显然,我得到了一个错误。我尝试使用“On Error Resume Next”修复它,但它只是使用最后一个有效的团队名称将错误填充到单元格中并继续。 所以我插入了一个处理程序(见下面的代码),让它将单元格留空并继续前进,当出现一个错误时它工作正常,但当出现 2 个连续错误时:
- 该宏会将第一个单元格留空,但会使用最后一个有效团队名称在第二个单元格中填充错误。
- 即使在列表结束后它也会继续填充,忽略我为循环提供的条件(下面代码中的 NumRows)。
哪位大神能指导一下错误处理流程怎么修改吗?
Sub populateteam()
Dim wbFollowUp As Workbook
Dim wbList As Workbook
Set wbFollowUp = ThisWorkbook
Set wbList = Workbooks.Open("C:\<folders>\CSTeams.xlsx")
Dim wsAkasaka As Worksheet
Dim wsList As Worksheet
Set wsAkasaka = wbFollowUp.Worksheets("Akasaka")
Set wsList = wbList.Worksheets("All Japan")
wbFollowUp.Activate
Dim consultant As String
Dim manager As String
Dim team As String
Dim x As Integer
Application.ScreenUpdating = False
NumRows = Range("b2", Range("b2").End(xlDown)).Rows.Count
For x = 1 To NumRows
consultant = wsAkasaka.Range("b" & (ActiveCell.Row)).Value
On Error GoTo handler:
manager = Application.VLookup(consultant, wsList.Range("a13:c250"), 3, False)
team = Application.VLookup(manager, wsList.Range("e2:F11"), 2, False)
'The name of the manager in the consultant list and in the team list should be exactly the same,
'including spaces before and after
If IsEmpty(ActiveCell.Value) Then
ActiveCell.Value = team
ActiveCell.Offset(1, 0).Select
End If
Next
Application.ScreenUpdating = True
handler:
ActiveCell.Value = ""
ActiveCell.Offset(1, 0).Select
Resume Next
End Sub
您的错误处理未按预期进行。如果您阅读 Resume Statement 的文档,它说 Resume Next
执行以下操作:
Execution resumes with the statement immediately following the statement that caused the error.
因此,如果 manager = Application.VLookup(consultant, wsList.Range("a13:c250"), 3, False)
中出现错误,因为找不到 consultant
。它将继续使用 next 行,即 team = Application.VLookup(manager, wsList.Range("e2:F11"), 2, False)
但由于 manager
未检索到,这再次进入错误处理程序。然后它再次处理 *next 行,即 If IsEmpty(ActiveCell.Value) Then
.
所以实际的问题是你使用了.Select
和ActiveCell
。您可能会从阅读 How to avoid using Select in Excel VBA 中获益。而不是使用 .Select
直接引用您的单元格(参见下面的代码):
Option Explicit
Public populateteam()
Dim wbFollowUp As Workbook
Set wbFollowUp = ThisWorkbook
Dim wbList As Workbook
Set wbList = Workbooks.Open("C:\<folders>\CSTeams.xlsx")
Dim wsAkasaka As Worksheet
Set wsAkasaka = wbFollowUp.Worksheets("Akasaka")
Dim wsList As Worksheet
Set wsList = wbList.Worksheets("All Japan")
Application.ScreenUpdating = False
Dim LastRow As Long
LastRow = wsAkasaka.Range("B2").End(xlDown).Row
Dim iRow As Long
For iRow = 2 To LastRow ' start in row 2 and run to last row if you want to start from the active cells row use `ActiveCell.Row` instead of 2
Dim consultant As String
consultant = wsAkasaka.Cells(iRow, "B").Value
Dim manager As Variant
manager = Application.VLookup(consultant, wsList.Range("A13:C250"), 3, False)
If Not IsError(manager) Then
Dim team As Variant
team = Application.VLookup(manager, wsList.Range("E2:F11"), 2, False)
'The name of the manager in the consultant list and in the team list should be exactly the same,
'including spaces before and after
If Not IsError(team) Then
With wsAkasaka.Cells(iRow, "B") 'replace "B" with the column letter where you want to write your team!
If IsEmpty(.Value) Then
.Value = team
End If
End With
End If
End If
Next iRow
Application.ScreenUpdating = True
End Sub
Note that the
"B"
in theWith
statement needs to be adjusted to the column where you want to write theteam
value!
在您看到的代码中,我完全通过像 wsAkasaka.Cells(iRow, "B").Value
这样的完整单元格引用消除了 ActiveCell
和 .Select
它现在使用循环中的索引 iRow
。
我还删除了错误处理并检查查找是否得出结果(这比错误处理更高效并且更容易完成)。因此,如果查找成功,代码只会继续执行以下步骤。如果发生错误,它会自动处理下一行 Next iRow
.
只是一个旁注。 Excel 的行数超过了 Integer
的处理能力。因此需要声明行计数变量 Long
。由于 VBA 中有 no benefit in using Integer
,我建议始终使用 Long
。
如果您单步执行代码 line-by-line,您可以自己找到这些问题。事实上,只要错误处理没有像您预期的那样工作,您就应该单步执行代码 line-by-line 以确切了解发生了什么。
对于你的第一期,
The macro would leave the first one in blank but populated the second cell with an error using the last valid team name.
想一想当您有新顾问时您的代码 运行s 发生了什么:
- 行
manager = Application.VLookup(consultant, wsList.Range("a13:c250"), 3, False)
会抛出一个错误。请注意,manager
的值 不会 更新,因此将保持之前的值。 - 您的代码通过
handler
块,用“”填充单元格,移动到下一个单元格,然后Resume Next
行直接将您带到team = Application.VLookup(manager, wsList.Range("e2:F11"), 2, False)
- 现在,
manager
的值与上次 运行 的值相同,因此team
的值将与上次 [=53] 的值相同=].
我对你的 If IsEmpty(ActiveCell.Value) Then
循环有点困惑,所以这个建议可能不是你想要完成的,但我建议在你的 [=19] 中添加一个 Else
子句=] 语句,然后将行 team = Application.VLookup(manager, wsList.Range("e2:F11"), 2, False)
移动到该 Else
子句下。当使用现有的 consultant
.
manager
值时,这只会将 team
写入单元格
关于你的第二期,
It keeps populating even after the list ended, ignoring the condition I gave it for the loop (NumRows in code below).
你检查过NumRows
的值了吗?这一行Range("b2", Range("b2").End(xlDown)).Rows.Count
的价值比你想象的要大得多:超过100万