Compare two columns in different workbooks - excel

I would appreciate if I can get help in creating this macro. I have two workbooks, and want to compare the specific column from 1st workbook, Ex: Column H with next work book, Ex: column A. After comparison highlight the matching cells in 1st workbook. I have tried below script for comparison, it is executing successfully, but not seeing any result.
Sub test()
Dim ws1 As Worksheet, ws2 As Worksheet, w(), i As Long
Dim r As Range, myCol As String
Set ws1 = ThisWorkbook.Sheets(1)
Set ws2 = Workbooks("workbook.xlsx").Sheets(1)
With CreateObject("VBScript.RegExp")
.Pattern = "^([a-z]|[a-h][a-z]|[a-i][a-v])$"
.IgnoreCase = True
Do
myCol = InputBox("Enter Column")
Loop While Not .test(myCol)
End With
With CreateObject("Scripting.Dictionary")
.comparemode = vbTextCompare
For Each r In ws1.Range(myCol & "1", ws1.Range(myCol & Rows.Count).End(xlUp))
If Not IsEmpty(r) And Not .exists(r.Value) Then
ReDim w(0): w(0) = r.Row
.Add r.Value, w
Else
w = .Item(r.Value)
ReDim Preserve w(UBound(w) + 1)
w(UBound(w)) = r.Row
.Item(r.Value) = w
End If
Next
For Each r In ws2.Range("a1", ws2.Range("a" & Rows.Count).End(xlUp))
If .exists(r.Value) Then
For i = 0 To UBound(.Item(r.Value))
ws1.Range(myCol & .Item(r.Value)(i)).Offset(, 1).Resize(, 23).Value = _
r.Offset(, 1).Resize(, 23).Value
Next
End If
Next
End With
Set ws1 = Nothing: Set ws2 = Nothing
End Sub

Try
Sub test()
Dim ws1 As Worksheet, ws2 As Worksheet, w(), i As Long, n As Integer
Dim r As Range, myCol As String, wbname As String, msg As String
Set ws1 = ThisWorkbook.Sheets(1)
Dim myworkbooks As Variant, mycolors As Variant
' workbooks to compare
myworkbooks = Array("Workbook1.xlsx", "Workbook2.xlsx", "Workbook3.xlsx")
mycolors = Array(vbYellow, vbGreen, vbBlue)
' select column
With CreateObject("VBScript.RegExp")
.Pattern = "^([a-z]|[a-h][a-z]|[a-i][a-v])$"
.IgnoreCase = True
Do
myCol = InputBox("Enter Column")
Loop While Not .test(myCol)
End With
' build dictionary
With CreateObject("Scripting.Dictionary")
.comparemode = vbTextCompare
For Each r In ws1.Range(myCol & "1", ws1.Range(myCol & Rows.Count).End(xlUp))
If IsEmpty(r) Then
' skip empty cells
Else
If Not .exists(r.Value) Then
ReDim w(0): w(0) = r.Row
.Add r.Value, w
Else
w = .Item(r.Value)
ReDim Preserve w(UBound(w) + 1)
w(UBound(w)) = r.Row
.Item(r.Value) = w
End If
End If
Next
' compare and highlight match
For n = 0 To UBound(myworkbooks)
Debug.Print "Opening " & myworkbooks(n)
msg = msg & vbCrLf & myworkbooks(n)
Set ws2 = Workbooks(myworkbooks(n)).Sheets(1)
For Each r In ws2.Range("a1", ws2.Range("a" & Rows.Count).End(xlUp))
If .exists(r.Value) Then
For i = 0 To UBound(.Item(r.Value))
ws1.Range(myCol & .Item(r.Value)(i)).Interior.color = mycolors(n)
Next
End If
Next r
Next n
End With
Set ws1 = Nothing: Set ws2 = Nothing
MsgBox "Completed scanning" & msg, vbInformation
End Sub

Related

VBA Split on column - multiple variables

I have a VBA code that splits my data into seperate worksheets, based on the variables in a chosen column.
This works great, however I have a few variables that I want in the same sheet, dispite having a different name.
Example:
In column B I have company A, B, C, D & E. These companies gets split into different worksheets.
However, company A & C has the same parent company, and therefore should be in the same worksheet.
How can i add this to my code, if I include a table like below in my file?
Column A
Column B
Company A
Group 'World'
Company B
Group 'Other'
Company C
Group 'World'
Company D
Group 'Other'
Company E
Group 'Other'
Sub Step1_split()
Dim lr As Long
Dim ws As Worksheet
Dim vcol, i As Integer
Dim icol As Long
Dim myarr As Variant
Dim title As String
Dim titlerow As Integer
'This macro splits data into multiple worksheets based on the variables on a column found in Excel.
'An InputBox asks you which columns you'd like to filter by, and it just creates these worksheets.
Application.ScreenUpdating = False
vcol = Application.InputBox(prompt:="Which column would you like to filter by?", title:="Filter column", Default:="2", Type:=1)
Set ws = ActiveSheet
lr = ws.Cells(ws.Rows.Count, vcol).End(xlUp).Row
title = "A1"
titlerow = ws.Range(title).Cells(1).Row
icol = ws.Columns.Count
ws.Cells(1, icol) = "Unique"
For i = 2 To lr
On Error Resume Next
If ws.Cells(i, vcol) <> "" And Application.WorksheetFunction.Match(ws.Cells(i, vcol), ws.Columns(icol), 0) = 0 Then
ws.Cells(ws.Rows.Count, icol).End(xlUp).Offset(1) = ws.Cells(i, vcol)
End If
Next
myarr = Application.WorksheetFunction.Transpose(ws.Columns(icol).SpecialCells(xlCellTypeConstants))
ws.Columns(icol).Clear
For i = 2 To UBound(myarr)
ws.Range(title).AutoFilter field:=vcol, Criteria1:=myarr(i) & ""
If Not Evaluate("=ISREF('" & myarr(i) & "'!A1)") Then
Sheets.Add(after:=Worksheets(Worksheets.Count)).Name = myarr(i) & ""
Else
Sheets(myarr(i) & "").Move after:=Worksheets(Worksheets.Count)
End If
ws.Range("A" & titlerow & ":A" & lr).EntireRow.Copy Sheets(myarr(i) & "").Range("A1")
'Sheets(myarr(i) & "").Columns.AutoFit
Next
ws.AutoFilterMode = False
ws.Activate
Application.ScreenUpdating = True
End Sub
I have tried adding an IF formula in the code, but have no idea how to do it.
Create a sheet named "Groups" for your table of relationships. Build an array of company names to use in the filter criteria.
Option Explicit
Sub Step1_split()
Dim wb As Workbook, wsGroups As Worksheet
Dim wsSrc As Worksheet, wsTarget As Worksheet
Dim rngFilter As Range, rngCopy As Range
Dim lastrow As Long, r As Long, grp As String
Dim i As Long, n As Long, arCrit, vcol
Set wb = ThisWorkbook
With wb
Set wsSrc = .Sheets(1) '.ActiveSheet
Set wsGroups = .Sheets("Groups") ' as req
End With
vcol = Application.InputBox( _
prompt:="Which column would you like to filter by ?", _
title:="Filter column", Default:="2", Type:=1)
If vcol = "False" Then Exit Sub ' cancel
' filter range
With wsSrc
lastrow = .Cells(.Rows.Count, vcol).End(xlUp).Row
Set rngFilter = .Cells(1, vcol).Resize(lastrow)
Set rngCopy = .Cells(1, 1).Resize(lastrow)
.AutoFilterMode = False
End With
' get parent-company details
Dim dict As Object, k
Set dict = CreateObject("Scripting.Dictionary")
With wsGroups
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For r = 2 To lastrow
grp = Trim(.Cells(r, "B"))
If Not dict.exists(grp) Then
dict.Add grp, New Collection
End If
dict(grp).Add Trim(.Cells(r, "A"))
Next
End With
' create sheet for each group, clear existing
Application.ScreenUpdating = False
i = wb.Sheets.Count
For Each k In dict.keys
grp = Replace(CStr(k), "'", "") ' take out single quotes
On Error Resume Next
Set wsTarget = wb.Sheets(grp)
On Error GoTo 0
If wsTarget Is Nothing Then
wb.Sheets.Add(after:=wb.Sheets(i)).Name = grp
i = i + 1
Set wsTarget = wb.Sheets(i)
Else
wsTarget.Cells.Clear
End If
' create aray
ReDim arCrit(0 To dict(k).Count - 1)
For n = 1 To dict(k).Count
arCrit(n - 1) = dict(k)(n)
Next
'Debug.Print k, Join(arCrit, ";")
' filter with array as criteria and copy
With rngFilter
.AutoFilter Field:=1, Criteria1:=arCrit, _
Operator:=xlFilterValues
rngCopy.Copy wsTarget.Range("A1")
End With
Set wsTarget = Nothing
Next
wsSrc.AutoFilterMode = False
Application.ScreenUpdating = True
MsgBox "Done"
End Sub

Excel VBA Find all Key values, Make a comma separated Unique List of Values

Sub POs()
Const csQuery As String = "Query"
Dim lRow As Long
Dim sName As String
Dim rFind As Range
Dim rRows As Dictionary
Dim rData As Range
Dim sFirstMatch As String
Dim ws As Worksheet
input_lRow = ThisWorkbook.Worksheets(Sheet5.Name).Cells(Rows.Count, 1).End(xlUp).Row
data_lRow = ThisWorkbook.Worksheets(Sheet6.Name).Cells(Rows.Count, 1).End(xlUp).Row
Set rData = ThisWorkbook.Worksheets(Sheet6.Name).Columns("A")
Set rInput = ThisWorkbook.Worksheets(Sheet5.Name).Range("A2:A" & input_lRow)
Set rOutput = ThisWorkbook.Worksheets(Sheet5.Name)
Set rRows = New Dictionary
For Each c In rInput
sName = c
Set rFind = rData.Find(sName)
If rFind Is Nothing Then
rOutput.Range("J" & c.Row).Value = "No PO Found"
Else
sFirstMatch = rFind.Address
Do
Set rFind = rData.FindNext(rFind)
rRows.Add Key:=sName, Item:=rFind.Offset(, 2)
On Error Resume Next
Loop While rFind.Address <> sFirstMatch
End If
Next c
End Sub
This is what I have so far; it creates the dictionary. The part I am having a hard time with is If the KEY in the dictionary matches the value of the cell in rOutput Column A, then put all the ITEM values in a comma separated list in cell J
Psuedo Code:
If KEY = rOutput.Range("A2") THEN rOutput.Range("J2").Value = JOIN(rRows.Item,", ")
Here is what I tried:
Sub POs()
Const csQuery As String = "Query"
Dim lRow As Long
Dim sName As String
Dim rFind As Range
Dim rRows As Dictionary
Dim rData As Range
Dim sFirstMatch As String
Dim ws As Worksheet
input_lRow = ThisWorkbook.Worksheets(Sheet5.Name).Cells(Rows.Count, 1).End(xlUp).Row
data_lRow = ThisWorkbook.Worksheets(Sheet6.Name).Cells(Rows.Count, 1).End(xlUp).Row
Set rData = ThisWorkbook.Worksheets(Sheet6.Name).Columns("A")
Set rInput = ThisWorkbook.Worksheets(Sheet5.Name).Range("A2:A" & input_lRow)
Set rOutput = ThisWorkbook.Worksheets(Sheet5.Name)
Set rRows = New Dictionary
For Each c In rInput
sName = c
Set rFind = rData.Find(sName)
If rFind Is Nothing Then
rOutput.Range("J" & c.Row).Value = "No PO Found"
Else
sFirstMatch = rFind.Address
Do
Set rFind = rData.FindNext(rFind)
rRows.Add Key:=sName, Item:=rFind.Offset(, 2)
On Error Resume Next
Loop While rFind.Address <> sFirstMatch
End If
For Each Key In rRows.Keys
If Key = sName Then
rOutput.Range("J" & c.Row).Value = Join(rRows.Items, ", ")
End If
Next Key
Next c
End Sub
The problem with this is that it is not restarting the dictionary for each row. When I tried to Set rRows = New Dictionary before the Next c, I only ever get a single PO again.
How can I fix this to give me all unique POs for each of the rows in the input sheet?
The proposed solution below:
Uses one dictionary for the entire process instead of one per row.
Uses the dictionary to hold the values of the cells found, instead of the ranges.
Updates the output only once after the For…Next loop has been completed.
Sub POs_MATCH()
Dim oDtn As Dictionary
Dim rPOs As Range, rOutput As Range
Dim aInput As Variant, vOP As Variant
Dim rFind As Range, s1stFnd As String
Dim sOutput As String, lRow As Long
Dim exCalc As XlCalculation
Rem Excel Properties OFF
With Application
.EnableEvents = False
.DisplayAlerts = False
.ScreenUpdating = False
exCalc = .Calculation
.Calculation = xlCalculationManual
.CalculateBeforeSave = False
End With
Set oDtn = New Dictionary
With ThisWorkbook
With .Worksheets("RnO Input Data")
lRow = -1 + .Cells(Rows.Count, 1).End(xlUp).Row
aInput = .Cells(2, 1).Resize(lRow).Value
Set rOutput = .Cells(2, 10).Resize(lRow)
End With
With .Worksheets("POs")
lRow = -1 + .Cells(Rows.Count, 1).End(xlUp).Row
Set rPOs = .Cells(2, 1).Resize(lRow)
End With: End With
For Each vOP In aInput
sOutput = vbNullString
Set rFind = rPOs.Find(vOP)
If rFind Is Nothing Then
oDtn.Add 1 + oDtn.Count, "No PO Found"
Else
s1stFnd = rFind.Address
Do
sOutput = sOutput & ", " & rFind.Offset(0, 2).Value
Set rFind = rPOs.FindNext(rFind)
Loop Until rFind.Address = s1stFnd
oDtn.Add 1 + oDtn.Count, Mid(sOutput, 3)
End If: Next
rOutput.Value = WorksheetFunction.Transpose(oDtn.Items)
Rem Excel Properties OFF
With Application
.Calculation = exCalc
.CalculateBeforeSave = True
.ScreenUpdating = True
.DisplayAlerts = True
.EnableEvents = True
End With
End Sub
I think I got it.
2 things:
I needed to swap what was a key and what was an item. I had them
backwards.
I had to move my loop around for the output into the Do
While and reset the dictionary outside of that loop.
input_lRow = ThisWorkbook.Worksheets("RnO Input Data").Cells(Rows.Count, 1).End(xlUp).Row
data_lRow = ThisWorkbook.Worksheets("POs").Cells(Rows.Count, 1).End(xlUp).Row
Set rData = ThisWorkbook.Worksheets("POs").Columns("A")
Set rInput = ThisWorkbook.Worksheets("RnO Input Data").Range("A2:A" & input_lRow)
Set rOutput = ThisWorkbook.Worksheets(Sheet5.Name)
Set rRows = New Dictionary
For Each c In rInput
Set rFind = rData.Find(c)
If rFind Is Nothing Then
rOutput.Range("J" & c.Row).Value = "No PO Found"
Else
sFirstMatch = rFind.Address
Do
rRows.Add Key:=rFind.Offset(, 2), Item:=c
Set rFind = rData.FindNext(rFind)
'On Error Resume Next
For Each k In rRows.Keys
If rRows.Item(k) = c Then
rOutput.Range("J" & c.Row).Value = Join(rRows.Keys, ", ")
End If
Next k
Loop While rFind.Address <> sFirstMatch
Set rRows = New Dictionary
End If
Next c
End Sub

Excel Macro updating rows in a file with new data

The code below runs and executes perfectly, I just want to add some features. The code imports the new rows from Report file to Workbook file, and I want it to check for a potential row with new data by every cell in the row, and not by just column G(contains number or numbers separated by comma), but in range A2:BQ. Also update the newly found cells even if the row exists in Workbook by the number in column G. Also to highlight the new rows with a bright color in the Workbook file. One last thing is to wrap the text after the importing of new cells finishes.
Sub Weekly_Report()
Const HAS_HEADER As Boolean = True 'Set true if the file has a header(Report)
Const NUM_COLS As Long = 69 '69 rows needed to be imported from the Report
Const FILENAME = "Report.xlsx"
Const PATH = "C:\Users\Documents\" 'path of the report
Dim wbReport As Workbook, wsReport As Worksheet, wsData As Worksheet
Dim next_blank_row As Long, iStartRow As Long, iLastRow As Long, iRow As Long
Dim sFilename As String
Set wsData = ThisWorkbook.Worksheets("Sheet1") 'for example: destination worksheet
next_blank_row = wsData.Cells(Rows.Count, "G").End(xlUp).Row + 1 'next blank row
sFilename = PATH & FILENAME
Debug.Print "Opening ", sFilename 'Openning file
On Error Resume Next
Set wbReport = Workbooks.Open(sFilename)
On Error GoTo 0
If wbReport Is Nothing Then
MsgBox "Can not open " & sFilename, vbCritical, "ERROR" 'If the file was not found or cannot be opened
Exit Sub
End If
Set wsReport = wbReport.Worksheets(1) 'Expects only one sheet in the Report
iStartRow = IIf(HAS_HEADER, 2, 1) 'If it has header start from row 2
iLastRow = wsReport.Cells(Rows.Count, 1).End(xlUp).Row
Dim s As String, rng As Range, m As Long
For iRow = iStartRow To iLastRow
s = CStr(wsReport.Cells(iRow, "G").Value)
Set rng = wsData.Columns("A:BQ").Find(s)
If rng Is Nothing Then
m = next_blank_row 'no match - use next blank row and increment
next_blank_row = next_blank_row + 1
Debug.Print iRow, s, "New row " & m
Else
m = rng.Row
Debug.Print iRow, s, "Match row " & m 'Match row:if the line already exists in the file
End If
wsData.Cells(m, 1).Resize(1, NUM_COLS).Value = wsReport.Cells(iRow, 1).Resize(1, NUM_COLS).Value 'Put the new line in Workbook
Next
MsgBox wsReport.Name & " scanned from row " & iStartRow & _
" to " & iLastRow, vbInformation, sFilename
wbReport.Close False 'Close the Report
End Sub
This updates column P and S for rows matching column G or adds the rows if no match.
Option Explicit
Sub Weekly_Report()
Const HAS_HEADER As Boolean = True 'Set true if the file has a header(Report)
Const NUM_COLS As Long = 69 '69 cells in the row needed to be imported from the Report
Const FILENAME = "Report.xlsx"
Const PATH = "C:\Users\Documents\" 'path of the report
Dim wbReport As Workbook, wsReport As Worksheet, wsData As Worksheet
Dim next_blank_row As Long, iStartRow As Long, iLastRow As Long, iRow As Long
Dim sFilename As String
Set wsData = ThisWorkbook.Worksheets("Sheet1") 'for example: destination worksheet
next_blank_row = wsData.Cells(Rows.Count, "G").End(xlUp).Row + 1 'next blank row
sFilename = PATH & FILENAME
Debug.Print "Opening ", sFilename 'Openning file
On Error Resume Next
Set wbReport = Workbooks.Open(sFilename)
On Error GoTo 0
If wbReport Is Nothing Then
MsgBox "Can not open " & sFilename, vbCritical, "ERROR" 'If the file was not found or cannot be opened
Exit Sub
End If
Set wsReport = wbReport.Worksheets(1) 'Expects only one sheet in the Report
iStartRow = IIf(HAS_HEADER, 2, 1) 'If it has header start from row 2
iLastRow = wsReport.Cells(Rows.Count, 1).End(xlUp).Row
Dim rng As Range, rng2 As Range, rng3 As Range
Dim m As Long, m2 As String, m3 As String, s As String, s2 As String, s3 As String, c As Variant
Dim iAdd As Long, iUpdate As Long
For iRow = iStartRow To iLastRow
s = CStr(wsReport.Cells(iRow, "G").Value)
Set rng = wsData.Columns("G").Find(s)
If rng Is Nothing Then
m = next_blank_row 'no match - use next blank row and increment
next_blank_row = next_blank_row + 1
With wsData.Cells(m, 1).Resize(1, NUM_COLS)
.Value = wsReport.Cells(iRow, 1).Resize(1, NUM_COLS).Value
.Interior.Color = vbYellow
End With
iAdd = iAdd + 1
Debug.Print iRow, s, "New row " & m
Else
m = rng.Row
For Each c In Array("P", "S")
If wsData.Cells(m, c) <> CStr(wsReport.Cells(iRow, c).Value) Then
wsData.Cells(m, c) = CStr(wsReport.Cells(iRow, c).Value)
wsData.Cells(m, c).Interior.Color = vbGreen
iUpdate = iUpdate + 1
End If
Next
Debug.Print iRow, s, "Match row " & m 'Match row:if the line already exists in the file
End If
Next
MsgBox wsReport.Name & " scanned from row " & iStartRow & _
" to " & iLastRow & vbCrLf & "added rows = " & iAdd & vbCrLf & _
"updated cells = " & iUpdate, vbInformation, sFilename
wbReport.Close False 'Close the Report
End Sub
Since you seem to be stuck on comparing two ranges:
'Do two ranges contain the same value(s)?
' does not handle error values...
Function RangesMatch(rng1 As Range, rng2 As Range) As Boolean
Dim rv As Boolean, v1, v2, r As Long, c As Long
If rng1.Rows.Count = rng2.Rows.Count And _
rng1.Columns.Count = rng2.Columns.Count Then
v1 = rng1.Value
v2 = rng2.Value
If rng1.Count = 1 Then
RangesMatch = (v1 = v2) 'single cell ranges...
Else
'multi-cell ranges: loop and compare values
For r = 1 To UBound(v1, 1)
For c = 1 To UBound(v1, 2)
If v1(r, c) <> v2(r, c) Then
Exit Function 'by default returns false
End If
Next c
Next r
RangesMatch = True
End If
End If
End Function
This is how far I got:
Sub Weekly_Report()
Const HAS_HEADER As Boolean = True 'Set true if the file has a header(Report)
Const NUM_COLS As Long = 69 '69 cells in the row needed to be imported from the Report
Const FILENAME = "Report.xlsx"
Const PATH = "C:\Users\Documents\" 'path of the report
Dim wbReport As Workbook, wsReport As Worksheet, wsData As Worksheet
Dim next_blank_row As Long, iStartRow As Long, iLastRow As Long, iRow As Long
Dim sFilename As String
Set wsData = ThisWorkbook.Worksheets("Sheet1") 'for example: destination worksheet
next_blank_row = wsData.Cells(Rows.Count, "G").End(xlUp).Row + 1 'next blank row
sFilename = PATH & FILENAME
Debug.Print "Opening ", sFilename 'Openning file
On Error Resume Next
Set wbReport = Workbooks.Open(sFilename)
On Error GoTo 0
If wbReport Is Nothing Then
MsgBox "Can not open " & sFilename, vbCritical, "ERROR" 'If the file was not found or cannot be opened
Exit Sub
End If
Set wsReport = wbReport.Worksheets(1) 'Expects only one sheet in the Report
iStartRow = IIf(HAS_HEADER, 2, 1) 'If it has header start from row 2
iLastRow = wsReport.Cells(Rows.Count, 1).End(xlUp).Row
Dim s As String, rng As Range, m As Long, m2 As String, m3 As String, s2 As String, s3 As String, rng2 As Range, rng3 As Range
For iRow = iStartRow To iLastRow
s = CStr(wsReport.Cells(iRow, "G").Value)
Set rng = wsData.Columns("G").Find(s)
s2 = CStr(wsReport.Cells(iRow, "P").Value)
Set rng2 = wsData.Columns("P").Find(s2)
s3 = CStr(wsReport.Cells(iRow, "S").Value)
Set rng3 = wsData.Columns("S").Find(s3)
If rng Is Nothing Then
m = next_blank_row 'no match - use next blank row and increment
next_blank_row = next_blank_row + 1
Debug.Print iRow, s, "New row " & m
Else
m = rng.Row
Debug.Print iRow, s, "Match row " & m 'Match row:if the line already exists in the file
m2 = rng2.Row
m3 = rng3.Row
End If
wsData.Cells(m, 1).Resize(1, NUM_COLS).Value = wsReport.Cells(iRow, 1).Resize(1, NUM_COLS).Value
wsData.Cells(m2, 1).Resize(1, NUM_COLS).Value = wsReport.Cells(iRow, 1).Resize(1, NUM_COLS).Value
wsData.Cells(m3, 1).Resize(1, NUM_COLS).Value = wsReport.Cells(iRow, 1).Resize(1, NUM_COLS).Value
Next
MsgBox wsReport.Name & " scanned from row " & iStartRow & _
" to " & iLastRow, vbInformation, sFilename
wbReport.Close False 'Close the Report
End Sub

excel vba compare 2 columns and list non matching results

I try to compare two columns and get the non-matching results listed somewhere else.
So far I've come up with the following:
Sub match_columns()
Dim i, Lastrow1, Lastrow3 As Integer
Dim found As Range
With Worksheets("sht1")
Lastrow1 = .Range("A" & Rows.Count).End(xlUp).Row
For i = 1 To Lastrow1
answer1 = .Range("A" & i).Value
Set found = Sheets("sht2").Columns("A:A").Find(what:=answer1)
If found Is Nothing Then
Set rngNM = .Range("A" & i.Row)
Else
Set rngNM = Union(rngNM, .Range("A" & i.Row))
End If
Next i
End With
If Not rngNM Is Nothing Then rngNM.Copy Worksheets("sht3").[A2]
Worksheets("sht3").[A1] = "title"
Lastrow3 = Sheets("sht3").Range("A" & Rows.Count).End(xlUp).Row
Sheets("sht3").Range("A2:A" & Lastrow3).Copy
End Sub
I currently get an "Runtime error 424; Object required" for the following:
Set rngNM = .Range("A" & i.Row)
Where is my code wrong?
Try this code
Sub Compare_Two_Columns()
Dim ws As Worksheet, sh As Worksheet, out As Worksheet, c As Range, i As Long, m As Long, k As Long
Application.ScreenUpdating = False
Set ws = ThisWorkbook.Worksheets("Sheet1")
Set sh = ThisWorkbook.Worksheets("Sheet2")
Set out = ThisWorkbook.Worksheets("Sheet3")
m = ws.Range("A" & Rows.Count).End(xlUp).Row
ReDim a(1 To m)
For i = 1 To m
Set c = sh.Range("A:A").Find(What:=ws.Cells(i, 1).Value, LookAt:=xlWhole)
If c Is Nothing Then k = k + 1: a(k) = ws.Cells(i, 1).Value
Next I
If k > 0 Then
With out
.Range("A1").Value = "Title"
.Range("A2").Resize(k).Value = Application.Transpose(a)
End With
End If
Application.ScreenUpdating = True
MsgBox "Done...", 64
End Sub

How to apply multiple criteria to .Find?

I adapted code I found online.
It finds the string "car" in column A and returns the rows as an array
It assigns a variable to the length of the array (how many matches it found)
It assigns a variable to generate a random number between 0 and the length of the array
It then prints a random matching row's value into K3
Dim myArray() As Variant
Dim x As Long, y As Long
Dim msg As String
With ActiveSheet.Range("A1:A" & ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row)
Set c = .find("Car", LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
ReDim Preserve myArray(y)
myArray(y) = c.Row
y = y + 1
Set c = .findNext(c)
If c Is Nothing Then
GoTo DoneFinding
End If
Loop While c.Address <> firstAddress
End If
DoneFinding:
End With
For x = LBound(myArray) To UBound(myArray)
msg = msg & myArray(x) & " "
Next x
ArrayLen = UBound(myArray) - LBound(myArray)
random_index = WorksheetFunction.RandBetween(0, ArrayLen)
MsgBox myArray(random_index)
Dim test As String
test = "B" & myArray(random_index)
Range("K3").Value = Range(test)
Example
I'm struggling with adapting the find code to allow for multiple criteria. So in my example, it finds "Car". What if I want to find matches that had "Car" in column A and "Red" in column D?
I tried
With ActiveSheet.Range("A1:A" & "D1:D" & ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row & ActiveSheet.Range("D" & Rows.Count).End(xlUp).Row)
Set c = .find("Car", "Red", LookIn:=xlValues)
I get type mismatch on the Set line.
In case it is confusing, it currently looks for a string e.g. "Car" but I will eventually link this to the variable which will be assigned to a data validation list. So if the user chooses "car" from a drop down list, this is what it will search for.
Maybe Advancde Filter is something that fit your needs:
Example Code
Option Explicit
Public Sub FilterData()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("YourSheetName")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim CriteriaRange As Range
Set CriteriaRange = ws.Range("A1", "E2")
Dim DataRange As Range
Set DataRange = ws.Range("A4", "E" & LastRow)
DataRange.AdvancedFilter Action:=xlFilterInPlace, CriteriaRange:=CriteriaRange, Unique:=False
End Sub
Public Sub ShowAll()
On Error Resume Next
ActiveSheet.ShowAllData
On Error GoTo 0
End Sub
Edit according comment:
You can use the advanced filter and then loop through the filter results:
Option Explicit
Public CurrentRow As Long
Public Sub FilterData()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("YourSheetName")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim CriteriaRange As Range
Set CriteriaRange = ws.Range("A1", "E2")
Dim DataRange As Range
Set DataRange = ws.Range("A4", "E" & LastRow)
DataRange.AdvancedFilter Action:=xlFilterInPlace, CriteriaRange:=CriteriaRange, Unique:=False
End Sub
Public Sub ShowAll()
On Error Resume Next
ActiveSheet.ShowAllData
CurrentRow = 1
On Error GoTo 0
End Sub
Public Sub GetNextResult()
FilterData
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("YourSheetName")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim DataRange As Range
Set DataRange = ws.Range("A4", "E" & LastRow)
Dim FilteredData As Range
Set FilteredData = DataRange.Resize(ColumnSize:=1).SpecialCells(xlCellTypeVisible)
If CurrentRow + 1 > FilteredData.Cells.Count Then
CurrentRow = 1
End If
CurrentRow = CurrentRow + 1
Dim i As Long
Dim Cell As Variant
For Each Cell In FilteredData
i = i + 1
If i = CurrentRow Then
Cell.EntireRow.Select
'or
'MsgBox Cell.Value & vbCrLf & Cell.Offset(0, 1) & vbCrLf & Cell.Offset(0, 2) & vbCrLf & Cell.Offset(0, 3) & vbCrLf & Cell.Offset(0, 4)
End If
Next Cell
End Sub

Resources