在VBA中搜索期间无响应状态

杰夫·克拉克

我正在创建一个工作簿,该工作簿将根据列中的值将数据从源工作表复制并粘贴到多个其他工作表。但是,一旦启动宏,Excel就会进入无响应状态。我在从4000到500,000行的任何地方进行操作,但是只有4列。当我只有约4000行时,它的工作速度非常快(3秒)。当我有约30,000行时,Excel进入约10秒的无响应状态,但随后完成。我没有等足够长的时间来进行300,000行测试。

我的想法过程是根据column中的字符串对所有数据进行排序B,将所有column B(包含我正在搜索的字符串)放入一个数组,然后将所有唯一的字符串拉出到另一个数组中。例如,如果列B在1-200行中保持“搜索”,而在201-500行中保持“创建”,则宏将在各行中进行搜索,第二个数组(称为Scenario)将最终保存两个值,“搜索”和“创建”。

在搜索过程中,我还创建了两个与Scenario数组相对应的并行数组,这些数组将保存该方案的开始行和结束行。之后,我将遍历并行数组中的值,并将其从源工作表复制/粘贴到其他工作表。

注意:排序工作正常

有没有办法使它更快?

这是代码:分配数据

Sub AllocateData()

Dim scenarioRange As String             'To hold the composite range
Dim parallelScenarioName() As String    'Holds the unique scenario names
Dim parallelScenarioStart() As Long     'Holds the starting row of the scenario
Dim parallelScenarioEnd() As Long       'Holds the ending row of the scenario

Sheets("raw").Activate                  'Raw is the source worksheet

'Populates the parallel scenario arrays
Call GetScenarioList(parallelScenarioName, parallelScenarioStart, parallelScenarioEnd)

'Loops through the scenario parallel array and coes the copy and paste to other worksheets
'Workseets are named the same as the scenarios
For intPosition = LBound(parallelScenarioName) To (UBound(parallelScenarioName) - 1)
    scenarioRange = "A" & parallelScenarioStart(intPosition) & ":" & "D" & parallelScenarioEnd(intPosition)
    Range(scenarioRange).Select
    Selection.Copy

    Worksheets(parallelScenarioName(intPosition)).Activate

    Range("A1").Select
    ActiveSheet.Paste
    Sheets("raw").Activate
Next

End Sub

GetScenarioList

Sub GetScenarioList(ByRef parallelScenarioName() As String, ByRef parallelScenarioStart() As Long, ByRef parallelScenarioEnd() As Long)
Dim scenarioName As Variant
Dim TotalRows As Long
Dim arraySize As Long
arraySize = 1

'Prep the parallel array for scenario name with the first value
ReDim parallelScenarioStart(1)
ReDim parallelScenarioName(1)
parallelScenarioStart(0) = 1                'First spot on the scenario start will be row 1

'Prep the first scenario name
'Sometimes a number will be attached on the end of the scenario name delimited by a period. Ignore it.
If (InStr(Cells(1, 2).Text, ".") <> 0) Then
    parallelScenarioName(0) = Left(Cells(1, 2).Text, InStr(Cells(1, 2).Text, ".") - 1)
Else
    parallelScenarioName(0) = Cells(1, 2).Text
End If

'Get the total amount of rows
TotalRows = Rows(Rows.Count).End(xlUp).row

'Loop through all of the rows
For i = 1 To TotalRows
    'Sometimes a number will be attached on the end of the scenario name delimited by a period. Ignore it.
    If (InStr(Cells(i, 2).Text, ".") <> 0) Then
        scenarioName = Left(Cells(i, 2).Text, InStr(Cells(i, 2).Text, ".") - 1)
    Else
        scenarioName = Cells(i, 2).Text
    End If

    'If the scenario name is not contained in the unique array
    If IsNotInArray(scenarioName, parallelScenarioName) Then
        Call AddScenarioEndRow(i, arraySize, parallelScenarioEnd)
        Call AddNewScenarioToParallelArray(scenarioName, arraySize, parallelScenarioName)
        Call AddNewScenarioStartRow(i, arraySize, parallelScenarioStart)
    End If
Next

'Cleanup. The above code did not cover the ending row of the last scenario
Call AddScenarioEndRow(TotalRows + 1, arraySize, parallelScenarioEnd)

End Sub

IsNotInArray

Function IsNotInArray(stringToBeFound As Variant, ByRef parallelScenarioName() As String) As Boolean
  IsNotInArray = Not (UBound(Filter(parallelScenarioName, stringToBeFound)) > -1)
End Function

平行阵列

Sub AddNewScenarioToParallelArray(str As Variant, arraySize As Long, ByRef parallelScenarioName() As String)
arraySize = UBound(parallelScenarioName) + 1
ReDim Preserve parallelScenarioName(arraySize)
parallelScenarioName(arraySize - 1) = str
End Sub

Sub AddScenarioEndRow(row As Variant, ByRef arraySize As Long, ByRef parallelScenarioEnd() As Long)
ReDim Preserve parallelScenarioEnd(arraySize)
parallelScenarioEnd(arraySize - 1) = row - 1
End Sub

Sub AddNewScenarioStartRow(row As Variant, ByRef arraySize As Long, ByRef parallelScenarioStart() As Long)
ReDim Preserve parallelScenarioStart(arraySize)
parallelScenarioStart(arraySize - 1) = row
End Sub
杰夫·克拉克

我的要求最终略有变化。质量保证负责人希望在原始工作表中使用元数据,因此我可以使用完整的场景列表,而不必查看原始数据中的每一行。结果,我可以将场景列表保存并排序到数组中,然后执行.Find(parallelScenarioName(intPosition + 1))。row以获取下一个场景的行。

由于此更改,我没有完全实现和测试将遍历数据中每一行的Tim Williams解决方案。我现在必须继续前进,但是我会根据自己的知识重新审视和测试Tim的解决方案。

完成的代码如下。

'This is in a module so that my subs can see it
Option Explicit
Public Const DATASOURCE_WORKSHEET As String = "raw"

'This is the macro is called. Can be considered main.
Sub AllocateImportedData()
    Call SortDataSourceWorksheet
    Call AllocateData
End Sub

Sub SortDataSourceWorksheet()
    Dim entireRangeToSort As String
    Dim colToSortUpon As String
    Dim lastRow As Long

    lastRow = FindLastRowOfRawData
    entireRangeToSort = ConstructRangeString("A", 1, "D", lastRow)
    colToSortUpon = ConstructRangeString("B", 1, "B", lastRow)

    Call SortRangeByColumnAtoZ(entireRangeToSort, colToSortUpon)
End Sub

Sub SortRangeByColumnAtoZ(entireRangeToSort As String, colToSortUpon As String)

    ActiveWorkbook.Worksheets(DATASOURCE_WORKSHEET).Sort.SortFields.Clear
    ActiveWorkbook.Worksheets(DATASOURCE_WORKSHEET).Sort.SortFields.Add Key:=Range(colToSortUpon), _
    SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets(DATASOURCE_WORKSHEET).Sort
    .SetRange Range(entireRangeToSort)
    .Header = xlGuess
    .MatchCase = False
    .Orientation = xlTopToBottom
    .SortMethod = xlPinYin
    .Apply
End With  
End Sub


Sub AllocateData()

    Dim scenarioRange As String             'To hold the composite range
    Dim parallelScenarioName() As String    'Holds the unique scenario names
    Dim parallelScenarioStart() As Long     'Holds the starting row of the scenario
    Dim parallelScenarioEnd() As Long       'Holds the ending row of the scenario

    Sheets(DATASOURCE_WORKSHEET).Activate

    Call PopulateParallelScenarioArrays(parallelScenarioName, parallelScenarioStart, parallelScenarioEnd)
    Call PerformAllocation(parallelScenarioName, parallelScenarioStart, parallelScenarioEnd)
    Call FinishByActivatingDesiredWorksheet(DATASOURCE_WORKSHEET)  
End Sub

Sub PerformAllocation(ByRef parallelScenarioName() As String, ByRef parallelScenarioStart() As Long, ByRef parallelScenarioEnd() As Long)

    For intPosition = LBound(parallelScenarioName) To (UBound(parallelScenarioName) - 1)
        scenarioRange = ConstructRangeString("A", parallelScenarioStart(intPosition), "D", parallelScenarioEnd(intPosition))
        Range(scenarioRange).Select
        Selection.Copy

        Worksheets(parallelScenarioName(intPosition)).Activate

        Range("A1").Select
        ActiveSheet.Paste
        Sheets(DATASOURCE_WORKSHEET).Activate
    Next 
End Sub

Sub PopulateParallelScenarioArrays(ByRef parallelScenarioName() As String, ByRef parallelScenarioStart() As Long, ByRef parallelScenarioEnd() As Long)
    Dim numberOfScenarios As Long

    numberOfScenarios = GetScenarioListFromRaw(parallelScenarioName)
    ReDim parallelScenarioStart(numberOfScenarios)
    ReDim parallelScenarioEnd(numberOfScenarios)
    Call GetStartAndEndRows(parallelScenarioName, parallelScenarioStart, parallelScenarioEnd)   
End Sub

Function GetScenarioListFromRaw(ByRef parallelScenarioName() As String) As Long

    Dim numberOfScenarios As Long
    Dim scenarioRange As String
    Const scenarioListStartColumn As String = "F"
    Const scenarioListStartRow As Long = "3"

    numberOfScenarios = GetNumberOfScenarios(scenarioListStartColumn, scenarioListStartRow)

    ReDim parallelScenarioName(numberOfScenarios)

    'Populate parallel scenario name
    For i = 0 To (numberOfScenarios - 1)
        scenarioRange = scenarioListStartColumn & (scenarioListStartRow + i)
        parallelScenarioName(i) = Range(scenarioRange).Text
    Next

    Call AtoZBubbleSort(parallelScenarioName)

    GetScenarioListFromRaw = numberOfScenarios

End Function

Function GetNumberOfScenarios(scenarioListStartColumn As String, scenarioListStartRow As Long)
    GetNumberOfScenarios = Range(scenarioListStartColumn & scenarioListStartRow, Range(scenarioListStartColumn & scenarioListStartRow).End(xlDown)).Rows.Count
End Function


Sub GetStartAndEndRows(ByRef parallelScenarioName() As String, ByRef parallelScenarioStart() As Long, ByRef parallelScenarioEnd() As Long)
    Dim TotalRows As Long
    Dim newScenarioRow As Long

    'Prep the parallel array for scenario name with the first value
    parallelScenarioStart(0) = 1                'First spot on the scenario start will be row 1

    'Get the total amount of rows
    TotalRows = Rows(Rows.Count).End(xlUp).row

    For intPosition = LBound(parallelScenarioName) To (UBound(parallelScenarioName) - 1)
        'Find the row of the next scenario
        newScenarioRow = Worksheets(DATASOURCE_WORKSHEET).Columns(2).Find(parallelScenarioName(intPosition + 1)).row

        'Next scenario row - 1 is going to be the end of the current row
        parallelScenarioEnd(intPosition) = newScenarioRow - 1

        'Set starting row of next scenario
        parallelScenarioStart(intPosition + 1) = newScenarioRow
    Next   
End Sub

Sub FinishByActivatingDesiredWorksheet(desiredWorksheet As String)
    Sheets(desiredWorksheet).Activate
    Range("A1").Select
End Sub

Sub AtoZBubbleSort(ByRef parallelScenarioName() As String)

    Dim s1 As String, s2 As String
    Dim i As Long, j As Long

    For i = LBound(parallelScenarioName) To UBound(parallelScenarioName)
        For j = i To UBound(parallelScenarioName)
            If UCase(parallelScenarioName(j)) < UCase(parallelScenarioName(i)) Then
                s1 = parallelScenarioName(j)
                s2 = parallelScenarioName(i)
                parallelScenarioName(i) = s2
                parallelScenarioName(j) = s1
            End If
        Next
    Next
End Sub

Sub ClearWorkbookCells()
    Dim anyWS As Worksheet

    For Each anyWS In ThisWorkbook.Worksheets
        Call ClearWorksheetCells(anyWS)
    Next    
End Sub

Sub ClearWorksheetCells(ws As Worksheet)
    ws.Activate

    ' Find the last row and create range var
    lastRow = FindLastRowOfRawData
    ClearRange = "A1:" & "D" & lastRow

    'Select the area to clear and perform clear
    ActiveSheet.Range(ClearRange).Select
    Selection.ClearContents
End Sub

Function FindLastRowOfRawData()
    FindLastRowOfRawData = Range("A1").End(xlDown).row
End Function

Function ConstructRangeString(startCol As String, startRow As Long, endCol As String, endRow As Long) As String
    ConstructRangeString = startCol & startRow & ":" & endCol & endRow
End Function

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

REST API中搜索的响应状态代码

来自分类Dev

segue之后,重用的ViewController中的搜索栏无响应

来自分类Dev

分区表在安装期间无响应

来自分类Dev

从COM对象执行功能期间“无响应”

来自分类Dev

分区表在安装期间无响应

来自分类Dev

访问VBA循环(无响应)

来自分类Dev

访问VBA循环(无响应)

来自分类Dev

Websocket错误:WebSocket握手期间错误:在状态行中找不到响应代码

来自分类Dev

Chrome在MVC视图中的循环期间无响应

来自分类Dev

SMTPlib在Python中无响应

来自分类Dev

VBA Excel宏执行后无响应

来自分类Dev

有状态会话Bean的消息驱动Bean无响应

来自分类Dev

处于空闲状态时,SKScene变得无响应

来自分类Dev

无服务器响应模板,带状态码

来自分类Dev

[jQuery / Datatable]:数据表无响应,禁用输入搜索

来自分类Dev

Outlook中的VBA搜索

来自分类Dev

Outlook中的VBA搜索

来自分类Dev

在Xcode断点(Mac)中无键盘响应

来自分类Dev

UrhoSharp中的后退按钮无响应

来自分类Dev

固定导航栏中的链接无响应

来自分类Dev

PHP中的Messenger Bot:无响应

来自分类Dev

如何在Rails中处理无响应

来自分类Dev

在oracle中对更新查询无响应

来自分类Dev

引导程序中的固定内容,无响应

来自分类Dev

在VBA(Excel)RegEx搜索期间不包括文本

来自分类Dev

弹性搜索中无节点可用异常

来自分类Dev

执行 VBA 代码使 Excel 无响应然后恢复

来自分类Dev

为什么在高IO(读/写)操作期间Ubuntu变得无响应?

来自分类Dev

试图安装Ubuntu 16.04服务器-语言选择期间键盘无响应