VBA newbie here. I did find some information out there about coding these loops but I'm having a very hard time figuring out if and/or how it applies to my specific needs, so thank you in advance for any help you can give.
In order to QA information before it's formatted and uploaded, I want to cycle through multiple groups of dynamic ranges and check the information against another column within that range. Each range is grouped by an email address in column D, and I need to make sure that the same email is also listed in column G (I am going to delete columns B-D before upload). Since each grouping could be anywhere from 1 to 100 rows, I have coded how to define the ranges (below), but how can I add a loop to perform the check in each group individually?
The output for all of this should be a message box that either says, "All clear!" if the code finds no errors, or "[Name] isn't listed. Please add their information before continuing." if they aren't listed.
I'm assuming I should do some sort of Do While or Do Until or For loop for this, but then I get confused conceptually on whether to declare my variables in or outside of the loops and then how to concatenate possibly multiple unlisted names into the same message box at the end.
Here's what I have so far:
Sub QANameIsListed()
'Declare the variables.
Dim nRow As Long
Dim nStart As Long, nEnd As Long
Dim sEmail As String
Dim sName As String
'Figure out what first email address is.
sEmail = Range("D2").Text
'Figure out where first group data starts.
For nRow = 1 To 65536
If Range("D" & nRow).Value = sEmail Then
nStart = nRow
End If
Exit For
Next nRow
'Figure out where first group data ends.
For nRow = nStart To 65536
If Range("D" & nRow).Value <> sEmail Then
nEnd = nRow
End If
Exit For
Next nRow
nEnd = nEnd - 1
'Check whether the name is listed in the second column.
With Range("G" & nStart & ":G" & nEnd)
sName = Range("B" & nStart).Text & " " & Range("C" & nStart).Text
Set c = .Find(sEmail)
If c Is Nothing Then
MsgBox (sName & " " & "isn't listed." _
& " " & "Please add their information before continuing.")
Else
MsgBox ("All clear!")
End If
End With
End Sub
I see no real question in your post. :) However, here's my take.
First, you are placing your
Exit For
in the wrong place. If you place it outside theIf---End If
block, then yourFor
loop will always exit before it reaches theNext nRow
.Second, you are looping through 65536 cells twice, which is not only resource intensive, it's not completely compatible as well. If my data was in row 65537, I'd totally evade the loop. In Excel 2007 onward, after all, there are a million available rows.
My suggestion is, use
Find
exclusively. We'll use it to find the first occurrence ofsEmail
from the top and the last occurrence ofsEmail
from the bottom. We'll return their row index for this. Of course, this works only with the assumption that your emails are sorted properly...The final part is very simple, but it can escape some beginners, so no worries there. What we do is, we declare the range as determined from the above, and we will loop inside this range. You were almost there, so that's excellent.
My modification of your code is untested, but it captures what you tried to achieve and then maybe some. There are some lines I took the liberty of completely removing as I found them unnecessary (
Set c = .Find(sEmail)
, for one). I also added some other "newbie-friendly" things, like aBoolean
check and the quick and dirty method for multiple lines in aMsgBox
.Code follows:
This doesn't end here, though, since this will only run properly for one email on your list, and that email is also located in
D2
which is wherenStart
is going to default to anyway. So, even with the code above, my next suggestion is: It's better to have a list of all unique emails somewhere else, then iterate over that, withsEmail
being equal to the email string of the current iteration.If this sounds nice, then let us know so we can apply it accordingly. Otherwise, this code will work correctly on your current set-up or request as it is. :)
Result of test with
sEmail
located inM2
rather thanD2
below:MASSIVE EDIT:
As per exchange with OP, the following should do the trick. Please note however, that for my convenience, I took the liberty of assuming that a list of unique e-mails of all team leaders are located somewhere. Modify the code as necessary. Code follows:
Screencap of result:
LAST EDIT (HOPEFULLY):
Following code takes into account not having the list in advance. This will create the list in Column J instead.
Results are the same. Hope this helps!
FOLLOW-UP EDIT:
When dealing with dictionaries, since it is not always you encounter a dictionary with only one item (at least in my experience),
Transpose
is usually the best way to print out the keys or items to a range. However, with only one item in the dictionary, it fails to print it out (never bothered checking exactly why). However, looping through the keys or items is just fine and should result into printing out that lone key/item. See following edit.Results are the same on multiple groups, and it will not error out when only one group is present.
Let me know if this helps.