为什么Application.Match在同一数据上多次运行时表现不一致?

时间:2017-10-04 14:56:58

标签: vba excel-vba excel

背景:

我有一个工作簿Outline.xlsm,具有五级层次结构。在第一个工作表(WS1)中,前三个级别描述前两列,而接下来的两个级别各自有两个列: Outline sample

在第二个工作表(WS2)中,没有第3级,但其他一切都是相同的。所有单元格都格式化为文本。

我有一些代码将每个第一级部分(" General thing")拆分为自己的工作簿,以允许用户对描述(以及其他一些字段)进行更改。然后,有问题的代码会从每个文件中获取并获取这些新描述,并将它们与ID号相匹配。这是一个消毒版本:

Option Explicit

Sub GatherData()

    'Set up for speed
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Application.Calculation = xlCalculationManual

    'Get files to be processed
    Dim DataFolder As String
    Dim DataFile As String
    DataFolder = "\\SomeNetworkLocation"
    DataFile = Dir(DataFolder & "\GeneralThing*.xlsx")

    'Define ranges to search
    Dim WS1_L1Rng As Range
    Dim L2rng As Range
    Dim L3rng As Range
    Set WS1_L1Rng = Worksheets("WS1").Range("A2", "A" & Range("N2").End(xlDown).Row)
    Set L2rng = Worksheets("WS1").Range("C2", "C" & Range("N2").End(xlDown).Row)
    Set L3rng = Worksheets("WS1").Range("E2", "E" & Range("N2").End(xlDown).Row)

    Dim WS2_L1Rng As Range
    Dim WS2_L2Rng As Range
    Set WS2_L1Rng = Worksheets("WS2").Range("A2", "A" & Range("K2").End(xlDown).Row)
    Set WS2_L2Rng = Worksheets("WS2").Range("C2", "C" & Range("K2").End(xlDown).Row)

    Dim MatchPos As Variant
    Dim WS1_SearchRng As Range
    Dim WS2_SearchRng As Range
    Dim Cell As Range

    'Find and copy data
    Do While DataFile <> ""
        Workbooks.Open Filename:=DataFolder & "\" & DataFile
        With Workbooks(DataFile).Worksheets("WS1")
            Set WS1_SearchRng = .Range("A2:" & "A" & .Range("A" & .Rows.Count).End(xlUp).Row & ",C2:" & "C" & .Range("C" & .Rows.Count).End(xlUp).Row & ",E2:" & "E" & .Range("E" & .Rows.Count).End(xlUp).Row)
        End With
        For Each Cell In WS1_SearchRng
            If IsNumeric(Left(Cell.Value2, 2)) Then
                Select Case Cell.Rows.OutlineLevel
                    Case Is < 4
                        MatchPos = Application.Match(Cell.Value2, WS1_L1Rng, 0)
                    Case 4
                        MatchPos = Application.Match(Cell.Value2, L2rng, 0)
                    Case 5
                        MatchPos = Application.Match(Cell.Value2, L3rng, 0)
                End Select
                If IsError(MatchPos) Then
                    Debug.Print "WS1 " & Cell.Value2
                Else
                    MatchPos = MatchPos + 1
                    Workbooks(DataFile).Worksheets("WS1").Range("A" & Cell.Row, "L" & Cell.Row).Copy Destination:=Workbooks("Outline.xlsm").Worksheets("WS1").Range("A" & MatchPos, "L" & MatchPos)
                End If
            End If
            DoEvents
        Next Cell
        If Workbooks(DataFile).Worksheets.Count > 1 Then
        With Workbooks(DataFile).Worksheets("WS2")
            Set WS2_SearchRng = .Range("A2:" & "A" & .Range("A" & .Rows.Count).End(xlUp).Row & ",C2:" & "C" & .Range("C" & .Rows.Count).End(xlUp).Row)
        End With
        For Each Cell In WS2_SearchRng
            If IsNumeric(Left(Cell.Value2, 2)) Then
                Select Case Cell.Rows.OutlineLevel
                    Case Is < 4
                        MatchPos = Application.Match(Cell.Value2, WS2_L1Rng, 0)
                    Case 4
                        MatchPos = Application.Match(Cell.Value2, WS2_L2Rng, 0)
                End Select
                If IsError(MatchPos) Then
                    Debug.Print "WS2 " & Cell.Value2
                Else
                    MatchPos = MatchPos + 1
                    Workbooks(DataFile).Worksheets("WS2").Range("A" & Cell.Row, "I" & Cell.Row).Copy Destination:=Workbooks("Outline.xlsm").Worksheets("WS2").Range("A" & MatchPos, "I" & MatchPos)
                End If
            End If
            DoEvents
        Next Cell
        End If
        With Workbooks(DataFile)
            .Save
            .Close
        End With
        DataFile = Dir
    Loop


    'Return to regular configuration
    Application.ScreenUpdating = True
    Application.EnableEvents = True
    Application.Calculation = xlCalculationAutomatic
End Sub

问题:

通常,当我去运行此代码时,Application.Match在尝试匹配WS2中的任何内容时会引发错误。它通常可以正常工作,如果我只是杀死执行并重新开始相同的数据(有时需要几次尝试)。很少,它在WS1中也找不到任何东西;再次,如果我只是重新启动执行它通常工作正常。有时一切都很好,第一次尝试。为什么它表现不一致?

1 个答案:

答案 0 :(得分:1)

监视对活动工作簿/工作表的隐式引用;这些指令在运行时引用的工作簿/工作表将取决于当时活动的工作簿/工作表,这通常是造成此类错误的原因。

您可以使用Rubberduck(我管理的开源VBIDE加载项目)轻松找到它们(以及其他潜在的代码问题)。

Range("N2")中的

Worksheets("WS1").Range("A2", "A" & Range("N2").End(xlDown).Row)将是一个。 Worksheets使用不合格的Workbook对象将是另一个。

Rubberduck code inspections toolwindow

解决方案是使用WorkbookWorksheet对象引用明确限定它们。