Home > OS >  Check columns in difference sheets same workbook vba
Check columns in difference sheets same workbook vba

Time:11-30

I just started playing with vba working to find a way to check two excel sheets.I went trough all the answers i could find here about comparing sheets in excel with vba and finally found this answer VBA - Compare Tables on 2 Sheets with Differences from R.Katnaan that gave the best result. So i am trying to adjust and implement it on my situation. The sheets are target and counting with an output sheet for the result. The sheets are dynamically changed of my choosing based on reference in the output sheet where the user decides the files to be checked though a dropdown list. The code always checks the column b with starting row 3 on both sheets target and counting.

The code is working but for large sheets ( more than 100 rows ) it takes to much time . example for a sheet with 3500 rows it took 3 minutes 45 seconds to bring the result and there are mistakes on it ( results missing). i would guess is the do while function but i am not sure.is there a way to optimize the code? Thank you in advance for your time.

Public Sub Compare_sheets()

    Dim targetSheet, countingSheet, outputSheet As Worksheet
    Dim startrow, outputRow, temptargetRow, tempcountingRow, countingRowCount, targetRowCount, totalRowCount, finishedcountingIndex As Integer
    Dim finishedcounting() As String
    Dim isExist As Boolean
    
    
    'Do in background
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    
    'Set sheets
    Set targetSheet = Sheets(Sheets("Compare Sheets").Range("C3").Value)
    Set countingSheet = Sheets(Sheets("Compare Sheets").Range("C4").Value)
    Set outputSheet = Sheets("Compare Sheets")

    'Set start row of each sheet for data
    startrow = 3
    outputRow = 2

    'Get row count from counting sheet and targetsheet
    countingRowCount = countingSheet.Range("b" & startrow).End(xlDown).Row
    targetRowCount = targetSheet.Range("b" & startrow).End(xlDown).Row
    
    'Check which is bigger
    If countingRowCount < targetRowCount Then
        totalRowCount = targetRowCount
    Else
        totalRowCount = countingRowCount
    End If
    'Set index
    finishedcountingIndex = 0

    'Re-define array
    ReDim finishedcounting(0 To totalRowCount - 1)

    'Set the start row
    temptargetRow = startrow

    'Here I looped with OR state, you can modify it to AND start if you want
    Do

        'Reset exist flag
        isExist = False

        'loop all row in counting sheet
        For tempcountingRow = 1 To totalRowCount Step 1

            'If row is not finished for checking.
            If UBound(Filter(finishedcounting, tempcountingRow)) < 0 Then

                'If all cell are equal
                If targetSheet.Range("b" & temptargetRow) = countingSheet.Range("b" & tempcountingRow) Then

                    'Set true to exist flag
                    isExist = True

                    'Store finished row
                    finishedcounting(finishedcountingIndex) = tempcountingRow

                    finishedcountingIndex = finishedcountingIndex   1

                    'exit looping
                    Exit For

                End If

            End If

        Next tempcountingRow

        'Show result
        outputSheet.Range("g" & outputRow) = targetSheet.Range("b" & temptargetRow)
        outputSheet.Range("h" & outputRow) = targetSheet.Range("c" & temptargetRow)
        outputSheet.Range("i" & outputRow) = targetSheet.Range("d" & temptargetRow)

        If isExist Then
            outputSheet.Range("f" & outputRow) = "FOUND"
        Else
            outputSheet.Range("f" & outputRow) = "MISSING"
        End If

        'increase output row
        outputRow = outputRow   1

        'go next row
        temptargetRow = temptargetRow   1

    Loop While targetSheet.Range("B" & temptargetRow) <> vbNullString ' Or targetSheet.Range("B" & temptargetRow) <> "" Or targetSheet.Range("C" & temptargetRow) <> ""

    'loop all row in counting sheet
    For tempcountingRow = 1 To totalRowCount Step 1

        'If row is not finished for checking.
        If UBound(Filter(finishedcounting, tempcountingRow)) < 0 Then

            'Show result
            outputSheet.Range("g" & outputRow) = countingSheet.Range("b" & tempcountingRow)
            outputSheet.Range("j" & outputRow) = countingSheet.Range("c" & tempcountingRow)
            'outputSheet.Range("C" & outputRow) = countingSheet.Range("C" & tempcountingRow)
            outputSheet.Range("f" & outputRow) = "ADDITIONAL"

            'increase output row
            outputRow = outputRow   1

        End If

    Next tempcountingRow
    
    'Update
    Application.ScreenUpdating = True
    Application.EnableEvents = True

End Sub 

CodePudding user response:

Use a Dictionary Object.

Option Explicit
Public Sub Compare_sheets2()

    Const ROW_START = 3
    Const COL_KEY = "B"

    Dim t0 As Single: t0 = Timer
    Dim wsTarget As Worksheet, wsCount As Worksheet, wsOutput As Worksheet
    Dim lastrow As Long, i As Long, rowOut As Long
    
    Dim dict As Object, key, ar
    Set dict = CreateObject("Scripting.Dictionary")
    
    Set wsOutput = Sheets("Compare Sheets")
    With wsOutput
        Set wsTarget = Sheets(.Range("C3").Value2)
        Set wsCount = Sheets(.Range("C4").Value2)
    End With
    
    With wsCount
        lastrow = .Cells(.Rows.Count, COL_KEY).End(xlUp).Row
        ar = .Range("B1:B" & lastrow).Value2
        For i = ROW_START To lastrow
            key = Trim(ar(i, 1))
            If dict.exists(key) Then
                MsgBox "Duplicate key '" & key & "'", vbExclamation, wsCount.Name & " Row " & i
            Else
                dict.Add key, i
            End If
        Next
    End With
    
    rowOut = 2
    With wsTarget
        lastrow = .Cells(.Rows.Count, COL_KEY).End(xlUp).Row
        ' FOUND or MISSING
        For i = ROW_START To lastrow
            key = Trim(.Cells(i, COL_KEY))
            
            ' check if col B value exists on wsCount
            If dict.exists(key) Then
                wsOutput.Cells(rowOut, "F") = "FOUND"
                dict(key) = 0 ' mark as found
            Else
                wsOutput.Cells(rowOut, "F") = "MISSING"
            End If
            wsOutput.Cells(rowOut, "G").Resize(, 3) = .Cells(i, COL_KEY).Resize(, 3).Value2
            rowOut = rowOut   1
        Next
    
        ' ADDITIONAL
        For Each key In dict.keys
           i = dict(key)  ' row on wsCount
           If i > 0 Then
               wsOutput.Cells(rowOut, "F") = "ADDITIONAL"
               wsOutput.Cells(rowOut, "G") = key
               wsOutput.Cells(rowOut, "J") = wsCount.Cells(i, "C").Value2
               rowOut = rowOut   1
           End If
        Next
    End With
     
    MsgBox lastrow - ROW_START   1 & " rows scanned on " & wsTarget.Name, _
            vbInformation, Format(Timer - t0, "0.0 secs")
    
End Sub
  • Related