When I call the function from Excel (in a cell):
=allVlookup(O24,A:D,3,"")
vs via vba
MsgBox allVlookup(Range("O24"), Range("A:D"), 3, "")
I get different results. When called from Excel, I only get the first match, but when calling from a vba test sub with identical parameters (except adding Range
to the arguments to allow the sub to run), I get the full results (which is more than one).
The function I am using is:
Public Function allVlookup(lookupRange As Range, tableRange As Range, colIndex As Integer, Optional delimiter As String = "") As String
Dim c As Range
Dim firstAddress As String
'MsgBox tableRange.Address ' this is correct
'With Sheets(4).Range("A1:C12").Columns(1)
'With Range("A1:C12").Columns(1)
'this doesn't allow things to work right either (???)
'Set tableRange = Range("A:D")
'Set lookupRange = Range("O24")
'search only the first column for matches
With tableRange.Columns(1)
Set c = .Find(what:=lookupRange.Value, LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
'add the delimiter
If (allVlookup <> "") Then
allVlookup = allVlookup + delimiter
End If
'append value to previous value
allVlookup = allVlookup + c.Offset(0, colIndex).Value
Set c = .FindNext(c)
'exit conditions
'no match found
If (c Is Nothing) Then
Exit Do
'we're back to start
ElseIf (c.Address = firstAddress) Then
Exit Do
End If
Loop
End If
End With
End Function
I am at a loss to explain why this is happening.
What can I do to get the outputs to be identical?
The reason why it only gives the first match is because of a bug. Please see this link (SECTION 5) at the bottom.
I have already filed it as a bug long time ago. If you read the above link then I have suggested an alternative code as well.
Extract from that link in case the link ever dies (which it shouldn't)
.FindNext doesn’t work in a User-Defined Function as expected. You can use it in a normal function.
Lets Say We have this data in Sheet1:
and in
Now if we paste the below code in a module and run it then we will get the expected result as
$A$1:$A$3
However it would not work as expected if you paste this function in a module and call it from a worksheet as (Say in Cell C1)
=FindRange(A1,A1:A5)
The code will only give you the 1st instance of the value found and ignore the rest
And hence the result that you will get is $A$2!!!
We need to approach this from a different angle.
Instead of using .FindNext we use .Find again till we get the desired result ($A$1:$A$3). See the code below which works:
Please, don't as for logic but here is solution which gives me the same results. Change
.Find
line into:and additionally change
.FindNext
into:Pleas keep also in mind that
tableRange
range should have column titles. If not, the results order would not be as expected at the first sight.Additional (EDITED) explanation for last sentence. If you have table of that type:
when searching of ABC in
range("A1:D3")
to get data from column D you would get as result:BCD
. To getABC
there should be column titles in the first row.