Doable entirely without VBA:
=INDEX(Sheet2!$C$1:$C$999, AGGREGATE(15, 6, ROW(Sheet2!$A$1:$A$999)/(--(Sheet2!$A$1:$A$999=$A1)*--(Sheet2!$B$1:$B$999=$B1)), 1), 1)
The obvious bit is the Index - replace the AGGREGATE with a MATCH, and you probably already recognise it:
=INDEX(Sheet2!$C$1:$C$999, MATCH(???), 1)
However, instead of using MATCH, we are using the AGGREGATE function
AGGREGATE(15, 6, ROW(Sheet2!$A$1:$A$999)/(--(Sheet2!$A$1:$A$999=$A1)*--(Sheet2!$B$1:$B$999=$B1)), 1)
- The first argument (
15) just tells us to look for the kth SMALLest value in a list. This is similar to using the SMALL function
- The second argument (
6) tells us to discard any error values in the list.
- The third argument is the list to look at - we'll break this down later
- The final argument (
1) tells us to get the 1st smallest value from the list - effectively MIN, but MIN doesn't play nicely with calculated lists
So, what is our List then. Let's look at the formula:
ROW(Sheet2!$A$1:$A$999)/(--(Sheet2!$A$1:$A$999=$A1)*--(Sheet2!$B$1:$B$999=$B1))
There are two important parts here - first, ROW(Sheet2!$A$1:$A$999) will output the row number that we want, so that we can use it in the INDEX. Secondly, we divide it by a value which will be 1 when Column A matches (--(Sheet2!$A$1:$A$999=$A1)) and Column B matches (--(Sheet2!$B$1:$B$999=$B1)), but 0 when either of them doesn't. And, anything divided by 0 gives a #DIV0! error - which means it is discarded from our list!
So, the output of the AGGREGATE is the smallest Row number where the values match. If there is no such row, then you will get a #NUM! error instead.