Home > database >  How to expend the code to transfer data from one spreadsheet to another based on multiple criteria
How to expend the code to transfer data from one spreadsheet to another based on multiple criteria

Time:01-29

I have a very large Excel file from which I transfer complete rows (not copy but cut) to another spreadsheet based on certain criteria.The searched criteria are not only names (string), it can also be numbers that start with e.g. 45*. My created code works fine for smaller files, but for larger ones it just takes too long, sometimes it even crashes. I would like to extend the code with more functions:

  1. Delete all existing tables except the main table.
  2. Search for several criteria (e.g. "Government", "Midmarket", "45", "Enterprise") that can occur in column "S" and create a new table for each criterion which were found in column "S" and transfer the complet row in a new sheet. The name of the new sheet should be the name of defined criterion.
  3. Show the progress via a status or progress bar.

Here is the code I currently use:

Sub VTest()

    Dim LastRow         As Long
    Dim CurrentRow      As Long
    Dim SourceSheetName As String

    SourceSheetName = "InstallBase"                                                 ' <--- Set this to name of the Source sheet
   
    Application.ScreenUpdating = False                                              ' Turn ScreenUpdating off to prevent screen flicker

   
    Sheets.Add after:=Sheets(SourceSheetName)                                       ' Add a new sheet after the Source sheet
    ActiveSheet.Name = "Midmarket"                                                      ' Assign a name to newly created sheet

    Sheets(SourceSheetName).Range("A1:AC1").Copy Sheets("Midmarket").Range("A1:AC1")    ' Copy Header rows from Source sheet to the new sheet

    LastRow = Sheets(SourceSheetName).Range("A" & Rows.Count).End(xlUp).Row         ' Determine Last used row in column A

    For CurrentRow = LastRow To 2 Step -1                                           ' Start at LastRow and work backwards, row by row, until beginning of data
        If Sheets(SourceSheetName).Range("S" & CurrentRow).Value Like "Midmarket" Then  '   If we encounter a 'Yes' in column S then copy the row to new sheet
            Sheets(SourceSheetName).Rows(CurrentRow).Copy Sheets("Midmarket").Range("A" & Rows.Count).End(xlUp).Offset(1)
            Sheets(SourceSheetName).Rows(CurrentRow).Delete                         '   Delete the row from the Source sheet that contained 'Yes' in column S
        End If
    Next                                                                            ' Continue checking previous row


    Application.ScreenUpdating = True                                               ' Turn ScreenUpdating back on
End Sub

The status or progress bar can look like this: enter image description here

CodePudding user response:

This should only take seconds so the progress bar is unnecessary.

Option Explicit

Sub VTest2()

    Const COL_FILTER = 19 ' S
    Const HDR = "A1:AC1"

    Dim wb As Workbook, wsSrc As Worksheet, ws As Worksheet
    Dim rng As Range, rng1 As Range
    Dim arCrit, i As Long, lastrow As Long, lastCol As Long
    Dim s As String
    Dim r1 As Long, r2 As Long
    Dim t0 As Single
    
    arCrit = Array("Government", "Midmarket", "45", "99", "123", "Enterprise", "ABC", "DEF")
    
    Set wb = ThisWorkbook
    Set wsSrc = wb.Sheets("InstallBase")
    
    ' uncomment this to create test data
    'Call CreateTestData(wsSrc, 10000, arCrit, COL_FILTER)
    
    ' Delete all existing tables except the main table.
    t0 = Timer
    Application.DisplayAlerts = False
    For Each ws In wb.Sheets
        If ws.Name <> wsSrc.Name Then
            ws.Delete
        End If
    Next
    Application.DisplayAlerts = True
        
    ' sort
    Application.ScreenUpdating = False
    With wsSrc
        lastrow = .Cells(.Rows.Count, COL_FILTER).End(xlUp).Row
        lastCol = .UsedRange.Columns.Count
        ' add row counter to preserve order
        For i = 1 To lastrow
           .Cells(i, lastCol   1) = i
        Next
        With .Sort
           .SortFields.Clear
           .SortFields.Add2 Key:=wsSrc.Cells(1, COL_FILTER), _
            SortOn:=xlSortOnValues, Order:=xlDescending, _
            DataOption:=xlSortNormal
            .SetRange wsSrc.UsedRange
            .Header = xlYes
            .MatchCase = False
            .Orientation = xlTopToBottom
            .SortMethod = xlPinYin
            .Apply
        End With
                
    End With
            
    ' loop criteria
    For i = LBound(arCrit) To UBound(arCrit)
        s = arCrit(i)
        On Error Resume Next
        Set ws = wb.Sheets(s)
        On Error GoTo 0
        ' create sheet or clear existing
        If ws Is Nothing Then
            Set ws = wb.Sheets.Add(after:=wsSrc)
            ws.Name = s
        Else
            ws.Cells.Clear
        End If
        wsSrc.Range(HDR).Copy ws.Range("A1")
        
        ' is this a * match
        If IsNumeric(s) Then s = s & "*"
        
        ' find first match
        Set rng = wsSrc.Columns(COL_FILTER).Find(s, LookIn:=xlValues, lookat:=xlWhole)
        If rng Is Nothing Then
        Else
            r1 = rng.Row ' first
            ' find last
            Do While rng.Offset(1) Like s
                Set rng = rng.Offset(1)
            Loop
            r2 = rng.Row
            
            Set rng = wsSrc.Range(HDR).Offset(r1 - 1).Resize(r2 - r1   1)
            Debug.Print s, r1, r2, r2 - r1, rng.Address
            
            rng.Copy ws.Range("A2")
            rng.EntireRow.Delete
            
        End If
        Set ws = Nothing
    Next
    
    ' restore order
     With wsSrc
        With .Sort
           .SortFields.Clear
           .SortFields.Add2 Key:=wsSrc.Cells(1, lastCol   1), _
            SortOn:=xlSortOnValues, Order:=xlAscending, _
            DataOption:=xlSortNormal
            .SetRange wsSrc.UsedRange
            .Header = xlYes
            .MatchCase = False
            .Orientation = xlTopToBottom
            .SortMethod = xlPinYin
            .Apply
        End With
        .Columns(lastCol   1).Delete
    End With
    Application.ScreenUpdating = True
    
    MsgBox wb.Sheets.Count - 1 & " sheets created", vbInformation, "Took " & Format(Timer - t0, "0.0 secs")
    
End Sub

Sub CreateTestData(ws, n, ar, c)
    Dim i As Long, j As Long, x, t0 As Single
    t0 = Timer
    ReDim x(1 To n, 1 To 29)
    For j = 1 To 29 'AC
        x(1, j) = "Header " & j
    Next
    For i = 2 To n
        For j = 1 To 29 'AC
           x(i, j) = Split(Cells(i, j).Address(0, 0, xlA1), ":")(0)
        Next
        ' 50% other data
        If Int(Rnd * 2) = 1 Then
            x(i, c) = ar(Rnd * UBound(ar))
            If IsNumeric(x(i, c)) Then
                x(i, c) = x(i, c) & Format(10000 * Rnd, "00000")
            End If
        Else
            x(i, c) = "Other data"
        End If
    Next

    With ws
        .Cells.Clear
        .Range("A1").Resize(n, 29) = x
    End With
    MsgBox i - 1 & " rows of test data created", vbInformation, _
          "Took " & Format(Timer - t0, "0.0 secs")
End Sub
  • Related