Dynamic VBA - Compare Tables on 2 Sheets for Differences

KristianH

New Member
Joined
Mar 9, 2022
Messages
3
Office Version
  1. 365
Platform
  1. Windows
I am new to VBA and was looking for help in writing a code that can compare two tables on 2 different sheets and show the difference.
The code need to be used on different tables that have diffrent sizes eg. one time the tables use collumn A to C and another time it can use A to K.

I have looked at ways to do it, but get really confused when I try to make it dynamic. I want it to find items that are missing from sheet "Old_Data" and add that entire row to sheet "Output"

Here's an example of what I am looking for given 2 sheets of data, and the final output.

Sheet: Old_Data
1AA1AA
2BB2BB
3CC3CC
4DD4
5EE5EE

Sheet: New_Data
1AA1AA
3CC3CC
2BB2CC
4DD4DD
6EE6EE

Sheet: Output
4DD4DD
6EE6EE

Thank you so much for the help
 

Excel Facts

Ambidextrous Undo
Undo last command with Ctrl+Z or Alt+Backspace. If you use the Undo icon in the QAT, open the drop-down arrow to undo up to 100 steps.
I have modified this code, but it replace the data in New_Data instead of copy the difference to Output.

VBA Code:
Sub DeleteRows()
  Dim sh1 As Worksheet, sh2 As Worksheet
  Dim rng As Range, rng2 As Range, f As Range, c As Range, var1 As Range, var2 As Range
  Dim cad As String
  Dim col1 As Long, col2 As Long, i As Long, hrow As Long
  Dim dic As Object
  
  'Fit to your data
  Set sh1 = Sheets("New_Data")
  Set sh2 = Sheets("Old_Data")
  Set var1 = sh1.Range("A1")    'On Sheet 1, Cell where header is (Variable1)
  Set var2 = sh1.Range("B1")    'On sheet 1, Cell where header is (Variable2)
  hrow = 1                      'single header row in sheet 2
  
  Set dic = CreateObject("Scripting.Dictionary")
  
  Set f = sh2.Rows(hrow).Find(var1.Value, , xlValues, xlWhole, , , False)
  If f Is Nothing Then MsgBox "Header " & var1 & " does not exist in sheet 2": Exit Sub
  col1 = f.Column
  Set f = sh2.Rows(hrow).Find(var2.Value, , xlValues, xlWhole, , , False)
  If f Is Nothing Then MsgBox "Header " & var2 & " does not exist in sheet 2": Exit Sub
  col2 = f.Column
  
  For Each c In sh2.Range(sh2.Cells(2, col1), sh2.Cells(Rows.Count, col1).End(3))
    dic(c.Value & "|" & sh2.Cells(c.Row, col2).Value) = Empty
  Next
  
  For i = var1.Row + 1 To sh1.Cells(Rows.Count, var1.Column).End(3).Row
    cad = sh1.Cells(i, var1.Column).Value & "|" & sh1.Cells(i, var2.Column).Value
    Set rng2 = Union(sh1.Cells(i, var1.Column), sh1.Cells(i, var2.Column))
    If dic.exists(cad) Then
      If rng Is Nothing Then Set rng = rng2 Else Set rng = Union(rng, rng2)
    End If
  Next
  
  If Not rng Is Nothing Then
    Application.ScreenUpdating = False
    rng.EntireRow.Delete
  End If
End Sub
 
Upvote 0
According to the initial post sample an Excel basics VBA demonstration for starters to paste only to the Output worksheet module :​
VBA Code:
Sub Demo1()
  Const S = "&""¤""&"
    Dim A$, F$, V
        UsedRange.Clear
    With Sheets("Old_Data").[A1].CurrentRegion.Columns
        F = .Item(1).Address(, , , True) & S & .Item(2).Address(, , , True) & S & .Item(3).Address(, , , True)
    End With
    With Sheets("New_Data").[A1].CurrentRegion.Columns
        F = "TRANSPOSE(IF(ISNA(MATCH(" & .Item(1).Address & S & .Item(2).Address & S & .Item(3).Address & "," & F
        V = Filter(.Parent.Evaluate(F & ",0)),ROW(" & .Item(1).Address & ")))"), False, False)
        If UBound(V) > -1 Then Range("A1:C" & UBound(V) + 1).Value2 = Application.Index(.Value2, Application.Transpose(V), [{1,2,3}])
    End With
End Sub
 
Last edited by a moderator:
Upvote 0

A$, should be removed from the Dim codeline …​
 
Upvote 0
To get the 4D row in your output, you would need to put all 3 fields into your dictionary (currently only 2). If you did put all 3 fields in then you would also get the 2D row in your output since the 3rd column is different.

With only minimal changes to your code and assuming the sheet "Output" exists, try this.
It adds code for a sh3 being the Output sheet, copies the New_Data into Output then deletes the matched items as you are currently doing but using the Output sheet instead.

VBA Code:
Sub DeleteRows()
  Dim sh1 As Worksheet, sh2 As Worksheet, sh3 As Worksheet
  Dim rng As Range, rng2 As Range, f As Range, c As Range, var1 As Range, var2 As Range
  Dim cad As String
  Dim col1 As Long, col2 As Long, i As Long, hrow As Long
  Dim dic As Object
  
  'Fit to your data
  Set sh1 = Sheets("New_Data")
  Set sh2 = Sheets("Old_Data")
  Set sh3 = Sheets("Output")
  Set var1 = sh1.Range("A1")    'On Sheet 1, Cell where header is (Variable1)
  Set var2 = sh1.Range("B1")    'On sheet 1, Cell where header is (Variable2)
  hrow = 1                      'single header row in sheet 2
  
  Set dic = CreateObject("Scripting.Dictionary")
  
  Set f = sh2.Rows(hrow).Find(var1.Value, , xlValues, xlWhole, , , False)
  If f Is Nothing Then MsgBox "Header " & var1 & " does not exist in sheet 2": Exit Sub
  col1 = f.Column
  Set f = sh2.Rows(hrow).Find(var2.Value, , xlValues, xlWhole, , , False)
  If f Is Nothing Then MsgBox "Header " & var2 & " does not exist in sheet 2": Exit Sub
  col2 = f.Column
  
  For Each c In sh2.Range(sh2.Cells(2, col1), sh2.Cells(Rows.Count, col1).End(3))
    dic(c.Value & "|" & sh2.Cells(c.Row, col2).Value) = Empty
  Next
  
  For i = var1.Row + 1 To sh1.Cells(Rows.Count, var1.Column).End(3).Row
    cad = sh1.Cells(i, var1.Column).Value & "|" & sh1.Cells(i, var2.Column).Value
    Set rng2 = Union(sh1.Cells(i, var1.Column), sh1.Cells(i, var2.Column))
    If dic.exists(cad) Then
      If rng Is Nothing Then Set rng = rng2 Else Set rng = Union(rng, rng2)
    End If
  Next
  
  If Not rng Is Nothing Then
    Application.ScreenUpdating = False
    
    sh3.Range(sh1.UsedRange.Address).Value = sh1.UsedRange.Value
    sh3.Range(rng.Address).EntireRow.Delete
    Application.ScreenUpdating = True
  End If
End Sub
 
Upvote 0
An Excel basics VBA demonstration variation to paste only to the Output worksheet module :​
VBA Code:
Sub Demo1v()
    Dim V, C%, Rw As Range, R&
        UsedRange.Clear
    With Sheets("Old_Data").[A1].CurrentRegion.Columns
        V = .Item(1).Address
        For C = 2 To .Count:  V = V & "&""¤""&" & .Item(C).Address:  Next
        V = .Parent.Evaluate(V)
    End With
    With Application
        .ScreenUpdating = False
    For Each Rw In Sheets("New_Data").[A1].CurrentRegion.Rows
        If .IsNA(.Match(Join(.Index(Rw.Value2, 1, 0), "¤"), V, 0)) Then R = R + 1: Rw.Copy Cells(R, 1)
    Next
        .ScreenUpdating = True
    End With
End Sub
 
Last edited by a moderator:
Upvote 0
In case of big data Demo1 revamped :​
VBA Code:
Sub Demo1r()
  Const S = "&""¤""&"
    Dim V, R&
        UsedRange.Clear
    With Sheets("Old_Data").[A1].CurrentRegion.Columns
        V = .Item(1).Address(, , , True) & S & .Item(2).Address(, , , True) & S & .Item(3).Address(, , , True)
    End With
        Application.ScreenUpdating = False
    With Sheets("New_Data").[A1].CurrentRegion.Columns
            V = "IF(ISNA(MATCH(" & .Item(1).Address & S & .Item(2).Address & S & .Item(3).Address & "," & V
        For Each V In .Parent.Evaluate(V & ",0)),ROW(" & .Item(1).Address & "))")
            If V Then R = R + 1: .Rows(V).Copy Cells(R, 1)
        Next
    End With
        Application.ScreenUpdating = True
End Sub
 
Upvote 0
To get the 4D row in your output, you would need to put all 3 fields into your dictionary (currently only 2). If you did put all 3 fields in then you would also get the 2D row in your output since the 3rd column is different.

With only minimal changes to your code and assuming the sheet "Output" exists, try this.
It adds code for a sh3 being the Output sheet, copies the New_Data into Output then deletes the matched items as you are currently doing but using the Output sheet instead.

VBA Code:
Sub DeleteRows()
  Dim sh1 As Worksheet, sh2 As Worksheet, sh3 As Worksheet
  Dim rng As Range, rng2 As Range, f As Range, c As Range, var1 As Range, var2 As Range
  Dim cad As String
  Dim col1 As Long, col2 As Long, i As Long, hrow As Long
  Dim dic As Object
 
  'Fit to your data
  Set sh1 = Sheets("New_Data")
  Set sh2 = Sheets("Old_Data")
  Set sh3 = Sheets("Output")
  Set var1 = sh1.Range("A1")    'On Sheet 1, Cell where header is (Variable1)
  Set var2 = sh1.Range("B1")    'On sheet 1, Cell where header is (Variable2)
  hrow = 1                      'single header row in sheet 2
 
  Set dic = CreateObject("Scripting.Dictionary")
 
  Set f = sh2.Rows(hrow).Find(var1.Value, , xlValues, xlWhole, , , False)
  If f Is Nothing Then MsgBox "Header " & var1 & " does not exist in sheet 2": Exit Sub
  col1 = f.Column
  Set f = sh2.Rows(hrow).Find(var2.Value, , xlValues, xlWhole, , , False)
  If f Is Nothing Then MsgBox "Header " & var2 & " does not exist in sheet 2": Exit Sub
  col2 = f.Column
 
  For Each c In sh2.Range(sh2.Cells(2, col1), sh2.Cells(Rows.Count, col1).End(3))
    dic(c.Value & "|" & sh2.Cells(c.Row, col2).Value) = Empty
  Next
 
  For i = var1.Row + 1 To sh1.Cells(Rows.Count, var1.Column).End(3).Row
    cad = sh1.Cells(i, var1.Column).Value & "|" & sh1.Cells(i, var2.Column).Value
    Set rng2 = Union(sh1.Cells(i, var1.Column), sh1.Cells(i, var2.Column))
    If dic.exists(cad) Then
      If rng Is Nothing Then Set rng = rng2 Else Set rng = Union(rng, rng2)
    End If
  Next
 
  If Not rng Is Nothing Then
    Application.ScreenUpdating = False
  
    sh3.Range(sh1.UsedRange.Address).Value = sh1.UsedRange.Value
    sh3.Range(rng.Address).EntireRow.Delete
    Application.ScreenUpdating = True
  End If
End Sub

The only problem i have now is then I change the tables it need to compare to be 8x8 or something diffrent then 3x3
 
Upvote 0
It is unclear as to what you are trying to compare. Like I said, you have 3 columns but you only seem to be comparing on 2.
How many columns need to match and if it is not all of them, which one(s) are not to be included in the match ?
 
Upvote 0
The only problem i have now is then I change the tables it need to compare to be 8x8 or something diffrent then 3x3
Very not a problem if you have tried one of my demonstrations ! :rolleyes:
 
Upvote 0

Forum statistics

Threads
1,214,584
Messages
6,120,384
Members
448,956
Latest member
JPav

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top