Reputation:
I want to find out if a particular group of cells match another group of cells in a different sheet using VBA. In my case, I need to find out if the lastName, firstName
cells match. In my solution that I came up with, I'm looping through the first table, getting the employee name. Then looping through the second table, getting the employee name. Then seeing if the two match up. This method is too costly and takes too long. Is there any better way to do this?
My first table contains 6 rows, my second table can contain 100+ rows. Too much time is wasted.
I was thinking about just searching down the entire column to see if the last name matches first, if it does, then go and see if the first name matches... but then again, there could be some people with the same last name..
Here is what I have so far.
For i = 2 To managerRows 'Looping through the Managers Table
empFirst = managerSheet.Cells(i, 1)
empLast = managerSheet.Cells(i, 2)
empName = (empLast & ", " & empFirst)
For j = 3 To assignRows 'Looping through the Assignments table
empLastAssign = assignSheet.Cells(i, 4)
empFirstAssign = assignSheet.Cells(i, 5)
empNameAssign = (empLastAssign & ", " & empFirstAssign)
'MsgBox (empNameAssign)
...
Conditional statement comparing names
...
Next j
Next i
I know I have no conditional statement, I didn't bother writing it because I knew this approach is not the best one.
I cannot add another column to concatenate the second sheets names because they are read from a database and kept in separate columns and last name and first name. Anyways, is there a way that I can concatenate the names without adding another column to the second sheet and try to find them that way? Does that make sense?
Find
will only look in one column if I'm not mistaken. Can it look in two?
UPDATE
I'm able to get the first occurrence of the last name, but not the others. I've added another field to match. So there are three fields to match now. Last Name
, First Name
, and Project Name
. So far, my code will only find the first occurrence and stay there. I think my order of the looping is wrong.
Here is what I have so far.
For i = 2 To managerRows 'Looping through the Managers Table
empLast = managerSheet.Cells(i, 1)
empFirst = managerSheet.Cells(i, 2)
empName = (empLast & ", " & empFirst)
projectName = managerSheet.Cells(i, 3)
managerLast = managerSheet.Cells(i, 4)
managerFirst = managerSheet.Cells(i, 5)
managerName = (managerLast & ", " & managerFirst)
Set findRow = assignSheet.Range(assignSheet.Cells(3, 4), assignSheet.Cells(assignRows, 4)) 'Set a range to look for Last Name
Set c = findRow.Find(empLast, LookIn:=xlValues) 'Find matching Last Name if it exists
If Not c Is Nothing Then 'Last Name found
Do Until c Is Nothing 'Is this in the wrong place?
If Cells(c.Row, 5) = empFirst Then 'If first name matches
If Cells(c.Row, 10) = projectName Then 'If project name matches. We found them
MsgBox ("Found: " & empLast & ", " & empFirst & ": Project: " & projectName & " : in: " & c.Row)
End If
End If
Set c = findRow.FindNext(c) 'Is this is the wrong place?
Loop
End If
Set c = Nothing 'Is this in the wrong place?
Next i
Take a look at 'Is this in the wrong place?
for my new loop.
UPDATE 2: Solved
I have successfully filtered on three columns using find
and findNext
. With the help of some good answers. I will post the completed version. I had to add extra else statement into my filters in order to go to the next ling found. Hopefully others can learn from this, as there is no clear answer for filtering on three columns using find
.
For i = 2 To managerRows 'Looping through the Managers Table
empLast = managerSheet.Cells(i, 1)
empFirst = managerSheet.Cells(i, 2)
empName = (empLast & ", " & empFirst)
projectName = managerSheet.Cells(i, 3)
managerLast = managerSheet.Cells(i, 4)
managerFirst = managerSheet.Cells(i, 5)
managerName = (managerLast & ", " & managerFirst)
'Focus Below this
Set findRow = assignSheet.Range(assignSheet.Cells(3, 4), assignSheet.Cells(assignRows, 4)) 'Set a range to look for Last Name
Set c = findRow.Find(empLast, LookIn:=xlValues) 'Find matching Last Name if it exists
If Not c Is Nothing Then 'Last Name found
Do Until c Is Nothing
If Cells(c.Row, 5) = empFirst Then 'If first name matches
If Cells(c.Row, 10) = projectName Then 'If project name matches. We found them
MsgBox ("Found: " & empLast & ", " & empFirst & ": Project: " & projectName & " : in: " & c.Row)
Set c = Nothing
Else
Set c = findRow.FindNext(c)
End If
Else
Set c = findRow.FindNext(c)
End If
Loop
End If
Next i
Upvotes: 1
Views: 136
Reputation: 5151
Instead of using two loops, you can use just the first one and utilize the find
function. I believe it'll be faster for you.
For i = 2 To managerRows 'Looping through the Managers Table
empFirst = managerSheet.Cells(i, 1)
empLast = managerSheet.Cells(i, 2)
empName = (empLast & ", " & empFirst)
managerLast = managerSheet.Cells(i, 3)
managerFirst = managerSheet.Cells(i, 4)
managerName = (managerLast & ", " & managerFirst)
MsgBox (empName & ", " & managerName)
Set myRng = assignSheet.Range(assignSheet.Cells(3, 4), assignSheet.Cells(assignRows, 4)
Set c = myRng.Find(empName, lookin:=xlValues)
if Not c is Nothing Then 'you found last name, no look to see if first is a match
if assignSheet.cells(c.row, 5) = empFirst then 'if it is, do something
'do whatever you need to do here
else
firstAddress = c.Address
Do
Set c = myRng.FindNext(c)
if Not c is Nothing Then 'you found last name, no look to see if first is a match
if assignSheet.cells(c.row, 5) = empFirst then 'if it is, do something
'do whatever you need to do here
end if
end if
Loop While Not c Is Nothing And c.Address <> firstAddress
end if
end if
Next i
For more information on find
, look here.
Upvotes: 1
Reputation: 7979
you only need to know if it is there... then use COUNTIFS like:
=COUNTIFS(A:A,"Name",B:B,"Lastname"....)
and if it is not 0 then there is a match.
For VBA it is
Application.Countifs(Range("A:A"),"Name",Range("B:B"),"Lastname"....)
If you have any questions left, just ask ;)
EDIT
... I need the row number that they exist in ...
You never said that! *angry face*... still, it is possible to do in a more or less fast way:
Sub test()
Dim val As Variant, rowNum As Variant
With Sheets("Sheet1")
val = Evaluate(Intersect(.Columns(1), .UsedRange).Address & "&"" --- ""&" & Intersect(.Columns(2), .UsedRange).Address)
rowNum = Application.Match("name" & " --- " & "firstname", val, 0)
If IsNumeric(rowNum) Then Debug.Print "Found at Row: " & rowNum Else Debug.Print "Nothing was found"
End With
End Sub
Upvotes: 1
Reputation:
I usually use a dictionary or collection when looking for duplicates. In this way I only have to loop through each list one time.
Sub FindDuplicates()
Dim empFirst As String, empLast As String, empName As String
Dim assignSheet As Worksheet, managerSheet As Worksheet
Dim i As Long, lastRow As Long
Dim d
Set assignSheet = Sheet2
Set managerSheet = Sheet1
Set d = CreateObject("Scripting.Dictionary")
With managerSheet
lastRow = .Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lastRow 'Looping through the Managers Table
empFirst = .Cells(i, 1)
empLast = .Cells(i, 2)
empName = (empLast & ", " & empFirst)
If Not d.exists(empName) Then d.Add empName, i
Next
End With
With assignSheet
lastRow = .Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lastRow 'Looping through the Managers Table
empFirst = .Cells(i, 4)
empLast = .Cells(i, 5)
empName = (empLast & ", " & empFirst)
If d.exists(empName) Then
Debug.Print "Match Found", empName, "assignSheet Row:" & i, "managerSheet Row:" & d(empName)
End If
Next
End With
End Sub
Upvotes: 0