XLOOKUP with Multiple Criteria?

BrettOlbrys1

Board Regular
Joined
May 1, 2018
Messages
128
Office Version
  1. 365
Platform
  1. Windows
Hello. I have two tables. The first table has an "Activation Code" and the "Date" the Activation code was used. The second table is a historical table of data based on that Activation Code.

Table 1
AB
1Activation CodeDate When Code Was Used
2123452/17/22
3123454/4/22
4123458/11/22

Table 2 - Historical Data
ABC
1Activation CodeDateValue
2123451/1/22Northeast
3123453/1/22Southeast
4123456/1/22Central
51234511/1/22West

What I need to do is look up an Activation Code's value from Table 1 based on the date it was used, against the Table 2 historical data, and return whatever the Activation Code's value was at that time.

So the result, when I look up the codes in Table 1, should be:

12345 on 2/17/22 = Northeast
12345 on 4/4/22 = Southeast
12345 on 8/11/22 = Central

How should the formula be constructed?
 
Both formulas of post #4 and #5 will calculate faster if you don't refer to the table as a NamedRange but as Range
So for example,
-if Table2 (Activation Code / Date / Value) are in B1:D100000
-the ActivationCode to be cheched is in I2 and downward and DateWhenCodeWasUsed is in J2 and downward
-then in K2 you might use
Excel Formula:
=LET(LFC,I2,LFD,J2,RESULT,FILTER($D$2:$D$150000,($B$2:$B$150000=LFC)*($C$2:$C$150000<=LFD)),INDEX(RESULT,COUNTA(RESULT)))
Copy then K2 downward
This will be faster when compared to using Table2[Value] and the other "table centred" names

If that result is still unacceptable, you might try the following macro:
VBA Code:
Sub ActivationSearcher()
Dim wOne, wTwo, oArr(), wDates(), wVal()
Dim L1Start As Range, L2Start As Range, dPos As Range
Dim myDic As Object, myK As String, Result As String
Dim I As Long, K As Long, mySplit, mySplit2, myMatch
'
Set L1Start = Sheets("Sheet2").Range("B2")      '<<< 1) The starting corner of the database
Set L2Start = Sheets("Sheet2").Range("I2")      '<<< 2) The starting point of the query param
Set dPos = Sheets("Sheet2").Range("L2")         '<<< 3) The starting point for the results
'
'myTim = Timer
wOne = Range(L1Start, L1Start.End(xlDown)).Resize(, 3).Value
Set myDic = CreateObject("Scripting.Dictionary")
'Store Dates & Values in the Dictionary:
For I = 1 To UBound(wOne)
    myK = wOne(I, 1)
    If myDic.Exists(myK) Then
        myDic.Item(myK) = myDic.Item(myK) & "," & CLng(wOne(I, 2)) & ";" & wOne(I, 3)
    Else
        myDic.Add (myK), CLng(wOne(I, 2)) & ";" & wOne(I, 3)
    End If
'If I = 100000 Then Debug.Print Timer - myTim: Stop
Next I
'Beep
'Second phase:
wTwo = Range(L2Start, L2Start.End(xlDown)).Resize(, 2).Value        'ActivationCode /Date
ReDim oArr(1 To UBound(wTwo), 1 To 1)
For K = 1 To UBound(wTwo)
    myK = wTwo(K, 1)
    If myDic.Exists(myK) Then
        mySplit = Split("0;0," & myDic.Item(myK), ",", , vbTextCompare)
        ReDim wDates(0 To UBound(mySplit))
        ReDim wVal(0 To UBound(mySplit))
        For J = 0 To UBound(mySplit)
            mySplit2 = Split(mySplit(J), ";", , vbTextCompare)
            wDates(J) = CLng(mySplit2(0))
            wVal(J) = mySplit2(1)
        Next J
        myMatch = Application.Match(CLng(wTwo(K, 2)), wDates)
        oArr(K, 1) = wVal(myMatch - 1)
    End If
Next K
dPos.Resize(UBound(oArr), 1).Value = oArr
End Sub

There are three parametres to set; see the lines marked <<<
<<< 1) The starting corner of the database ; this corresponds to B2 in the example I used for the formulas
<<< 2) The starting point of the query param ; this points to the first ActivationCode to search, and the Date is assumed to be the column next to it
<<< 3) The starting point for the results ; typically this is some column at the right of parametre <<< 2

For each ActivationCode + Date set in the query table (as defined by <<<2) it will search into the Database (as set by <<<1) and write in the output position (as set by <<<3) the corresponding Value

This will take manymany seconds to complete (depends on how many unique ActivationCode you have in the DataBase: the less they are repeated, the better) but only when you run it

Finally, you should consider using PowwerQuery, as suggested by SpillerBD (see above)
 
Upvote 0

Excel Facts

Can you AutoAverage in Excel?
There is a drop-down next to the AutoSum symbol. Open the drop-down to choose AVERAGE, COUNT, MAX, or MIN
Hi Alex
I may be completely wrong and I haven't tested with such but I think that with 120,000 rows the strings may become quite long and the manipulations relatively slow.
Anyway, the OP has some large realistic data so it will be easy to tell either way I suspect, but this is my approach. There is a lot of looping but it is in memory and it is in ever-decreasing sized loops assuming the following is true.

The tables are sorted by the Activation Date ..

I have also now taken account of the following and removed the formal table structure.
I have both tables currently setup as ranges.

It may still well be that Power Query is the way to go, but if vba is preferred this is something to test at least.

Original data/layout

BrettOlbrys1.xlsm
ABCDEFGH
1Activation CodeDate When Code Was UsedActivation CodeDateValue
22222215/05/2021123451/01/2022Northeast
32222218/01/2022222221/01/2022a
41234517/02/2022123451/03/2022Southeast
5123454/04/20222222215/04/2022b
62222215/04/2022123451/06/2022Central
71234515/04/20222222225/09/2022c
81234511/08/2022123451/11/2022West
91234516/09/2022
102222225/11/2022
Test


VBA Code:
Sub Activation_Value()
  Dim d As Object
  Dim a As Variant, b As Variant
  Dim i As Long, j As Long, StartRow As Long
  
  Set d = CreateObject("Scripting.Dictionary")
  b = Range("F1").CurrentRegion.Resize(, 3).Value
  With Range("A1").CurrentRegion.Resize(, 3)
    a = .Value
    a(1, 3) = "Value"
    For i = UBound(a) To 2 Step -1
        If Not d.Exists(a(i, 1)) Then d(a(i, 1)) = UBound(b)
        j = d(a(i, 1))
        Do Until (b(j, 2) <= a(i, 2) And b(j, 1) = a(i, 1)) Or j = 1
          j = j - 1
        Loop
        If j > 1 Then
          a(i, 3) = b(j, 3)
          d(a(i, 1)) = j
        Else
          a(i, 3) = "N/A"
        End If
    Next i
    .Value = a
  End With
End Sub

Results

BrettOlbrys1.xlsm
ABCDEFGH
1Activation CodeDate When Code Was UsedValueActivation CodeDateValue
22222215/05/2021N/A123451/01/2022Northeast
32222218/01/2022a222221/01/2022a
41234517/02/2022Northeast123451/03/2022Southeast
5123454/04/2022Southeast2222215/04/2022b
62222215/04/2022b123451/06/2022Central
71234515/04/2022Southeast2222225/09/2022c
81234511/08/2022Central123451/11/2022West
91234516/09/2022Central
102222225/11/2022c
Test
 
Upvote 0
Using PowerQuery to "Merge" your matching results will be tonnes faster. The in-sheet methods get teadious over about 60K+. I've endured 500k lookup tables which helped push into PowerQuery, which is now known as the Get Data.
The PQ results can come out as a new Table, so you will have to adjust to that.
I will try this out and let you know what happens.
 
Upvote 0

Forum statistics

Threads
1,215,022
Messages
6,122,726
Members
449,093
Latest member
Mnur

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