How VLOOKUP works
VLOOKUP searches the first column of a table from top to bottom, finds a match, then moves right to return a value from whichever column you specify.
Think of it like a phone book. You search by name (first column), then read across to get the phone number (your chosen column). VLOOKUP does this in milliseconds across thousands of rows.
The catch, and this trips up most people, is that VLOOKUP can only look to the right. Your lookup value must always be in the first column of your selected range. If your data is not structured this way, you need INDEX MATCH instead.
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
| lookup_value | any | ✓ Required | The value you want to find. Usually a cell reference like A2. Can be text, a number, or a cell reference. |
| table_array | range | ✓ Required | The range containing your data. VLOOKUP searches the first column of this range. Lock it with $ signs if you plan to copy the formula down. |
| col_index_num | number | ✓ Required | Which column to return, counted from the left of your table_array. Column 1 is the first column (the one being searched), column 2 is the next, and so on. |
| range_lookup | boolean | ✗ Optional | FALSE for exact match (almost always what you want). TRUE for approximate match. Only use this for sorted tables like commission tiers or tax brackets. |
VLOOKUP basic: find product price by code
You work in sales at TechDirect. A customer wants the price of product P-1042. Your catalog has 500 rows. One formula finds it instantly.
=VLOOKUP(G2,$A$1:$D$9,4,FALSE)- •
G2→ the product code you're looking up - •
$A$1:$D$9→ your product catalog (locked with $) - •
4→ return column 4 (the Price column) - •
FALSE→ exact match only
| A | B | C | D | E | F | G | H | I | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | Product Code | Product Name | Category | Price | Order | Product Code | Price | ||
| 2 | P-1001 | Wireless Mouse | Peripherals | $29.99 | PO-2024-001 | P-1042 | $349.99 | ||
| 3 | P-1015 | Mechanical Keyboard | Peripherals | $89.99 | PO-2024-002 | P-1156 | $129.99 | ↓ drag down | |
| 4 | P-1042 | 27" Monitor | Displays | $349.99 | PO-2024-003 | P-1001 | $29.99 | ||
| 5 | P-1088 | USB-C Hub | Accessories | $44.99 | |||||
| 6 | P-1103 | Laptop Stand | Accessories | $67.99 | |||||
| 7 | P-1156 | Webcam HD | Peripherals | $129.99 | |||||
| 8 | P-1201 | Desk Lamp LED | Lighting | $39.99 | |||||
| 9 | P-1247 | Cable Manager | Accessories | $14.99 |
VLOOKUP with IFERROR: handle missing values gracefully
Your lookup formula works perfectly until someone types an invalid product code. VLOOKUP returns #N/A and your report looks broken. Wrap every VLOOKUP in IFERROR. Every single one. No exceptions.
=IFERROR(VLOOKUP(E2,$A$2:$B$8,2,FALSE),"Not found")- •
E2→ the order's product code (the value being looked up) - •
$A$2:$B$8→ the catalog: codes in column A, prices in column B - •
If the code is found→ returns the matching price - •
If the code is missing→ returns "Not found" instead of #N/A
| A | B | C | D | E | F | G | |
|---|---|---|---|---|---|---|---|
| 1 | Code | Price | Order | Code | Price | ||
| 2 | P-1001 | $29.99 | PO-001 | P-1042 | $349.99 | ||
| 3 | P-1042 | $349.99 | PO-002 | P-9999 | Not found | ↓ drag down | |
| 4 | P-1156 | $129.99 | PO-003 | P-1001 | $29.99 | ||
| 5 | P-2024 | $44.99 | PO-004 | P-0000 | Not found | ||
| 6 | P-1088 | $19.99 | |||||
| 7 | P-1450 | $79.99 | |||||
| 8 | P-2107 | $14.99 | |||||
| 9 |
VLOOKUP across sheets: pulling data from another tab
Your employee list is on Sheet1. Salaries live on Sheet2 to keep them restricted. You need to pull each person's salary without combining the sheets.
=VLOOKUP(A2,Sheet2!A:E,2,FALSE)- •
A2→ the employee ID on Sheet1 - •
Sheet2!A:E→ the compensation table on Sheet2 (the Sheet2! prefix points to the other tab) - •
2→ return column 2 of Sheet2 (the Salary column) - •
FALSE→ exact match: IDs must match exactly
| A | B | C | D | E | F | G | H | |
|---|---|---|---|---|---|---|---|---|
| 1 | Employee ID | Name | Department | Title | Hire Date | Manager | Salary | |
| 2 | E-1001 | Sarah Chen | Finance | Senior Analyst | 2019-03-15 | Mark Lee | $72,000 | |
| 3 | E-1042 | James Miller | HR | HR Specialist | 2020-06-22 | Anna Park | $61,000 | ↓ drag down |
| 4 | E-1088 | Maria Santos | Marketing | Marketing Lead | 2018-11-04 | Tom Davis | $58,000 | |
| 5 | E-1103 | David Brown | Finance | Junior Analyst | 2021-08-12 | Mark Lee | $68,000 | |
| 6 | E-1156 | Emma Davis | IT | Systems Engineer | 2017-02-28 | Tom Davis | $91,000 | |
| 7 | E-1201 | Alex Kim | Sales | Account Manager | 2022-01-10 | Lisa Wong | $64,000 | |
| 8 | E-1245 | Rachel Wood | Engineering | Software Engineer | 2020-09-15 | Mike Chen | $85,000 | |
| 9 | E-1287 | Carlos Gomez | Operations | Ops Manager | 2019-12-01 | Anna Park | $76,000 | |
| 10 | E-1310 | Jenny Liu | Marketing | Content Writer | 2023-04-18 | Tom Davis | $52,000 | |
| 11 | E-1356 | Mark Reilly | Engineering | Senior Engineer | 2018-07-25 | Mike Chen | $98,000 | |
| 12 | ||||||||
| 13 | ||||||||
| 14 |
| A | B | C | D | E | |
|---|---|---|---|---|---|
| 1 | Employee ID | Salary | Bonus | Stock | Total Comp |
| 2 | E-1001 | $72,000 | $5,000 | $8,000 | $85,000 |
| 3 | E-1042 | $61,000 | $3,500 | $5,000 | $69,500 |
| 4 | E-1088 | $58,000 | $3,000 | $4,500 | $65,500 |
| 5 | E-1103 | $68,000 | $4,500 | $7,000 | $79,500 |
| 6 | E-1156 | $91,000 | $7,000 | $12,000 | $110,000 |
| 7 | E-1201 | $64,000 | $4,000 | $6,000 | $74,000 |
| 8 | E-1245 | $85,000 | $6,500 | $10,000 | $101,500 |
| 9 | E-1287 | $76,000 | $5,500 | $8,500 | $90,000 |
| 10 | E-1310 | $52,000 | $2,500 | $3,000 | $57,500 |
| 11 | E-1356 | $98,000 | $8,000 | $13,500 | $119,500 |
Sheet1 D2 looks up E-1001 on Sheet2 and pulls back $72,000. The Sheet2! prefix tells VLOOKUP exactly which tab to search. The rest of the formula works identically to a same-sheet lookup.
VLOOKUP with TRUE: the one time approximate match makes sense
Commission tiers. Tax brackets. Grade scales. These are the only real cases where VLOOKUP with TRUE makes sense, where you want to find which range a value falls into, not an exact match.
Critical requirement: your lookup table must be sorted in ascending order. If it is not, VLOOKUP returns garbage.
=VLOOKUP(B4,$E$2:$F$5,2,TRUE)- •
B4→ the rep's monthly sales (the value being matched against the tiers) - •
$E$2:$F$5→ the tier table (locked with $ since the same range applies to every row) - •
2→ return column 2 of the tier table (the rate) - •
TRUE→ approximate match: pick the largest tier ≤ the lookup value
| A | B | C | D | E | F | G | |
|---|---|---|---|---|---|---|---|
| 1 | Sales Rep | Monthly Sales | Commission | Sales From | Rate | ||
| 2 | Rachel Green | $8,500 | 5% | $0 | 5% | ||
| 3 | Tom Bradley | $24,300 | 8% | $10,000 | 8% | ||
| 4 | Maria Santos | $67,800 | 12% | $50,000 | 12% | ||
| 5 | Chris Evans | $112,400 | 15% | $100,000 | 15% | ||
| 6 | |||||||
| 7 | |||||||
| 8 | |||||||
| 9 |
The $ sign mistake: why your formula breaks when you copy it down
This is the most common VLOOKUP mistake in real workplaces. You write a perfect formula in row 2, drag it down to row 50, and the results look wrong. The table range shifted with the formula.
Watch it happen step by step. You type the formula in E2, then drag it down to fill E3 and E4. Because there are no $ signs anchoring the table_array, every drag shifts the lookup range one column to the right.
=VLOOKUP(D2,A2:B5,2,FALSE)- •
D2→ the code you're looking up - •
A2:B5→ the catalog range: rows 2 through 5 of columns A and B - •
2→ return column 2 (Price) - •
FALSE→ exact match
| A | B | C | D | E | F | |
|---|---|---|---|---|---|---|
| 1 | Code | Price | Lookup | Result | ||
| 2 | P-1001 | $29.99 | P-1042 | $349.99 | ||
| 3 | P-1042 | $349.99 | P-1001 | ↓ drag down | ||
| 4 | P-1156 | $129.99 | P-1042 | |||
| 5 | P-2024 | $44.99 | ||||
| 6 | ||||||
| 7 | ||||||
| 8 | ||||||
| 9 |
| A | B | C | D | E | F | |
|---|---|---|---|---|---|---|
| 1 | Code | Price | Lookup | Result | ||
| 2 | P-1001 | $29.99 | P-1042 | $349.99 | ||
| 3 | P-1042 | $349.99 | P-1001 | #N/A | ||
| 4 | P-1156 | $129.99 | P-1042 | ↓ drag down | ||
| 5 | P-2024 | $44.99 | ||||
| 6 | ||||||
| 7 | ||||||
| 8 | ||||||
| 9 |
| A | B | C | D | E | F | |
|---|---|---|---|---|---|---|
| 1 | Code | Price | Lookup | Result | ||
| 2 | P-1001 | $29.99 | P-1042 | $349.99 | ||
| 3 | P-1042 | $349.99 | P-1001 | #N/A | ||
| 4 | P-1156 | $129.99 | P-1042 | #N/A | ||
| 5 | P-2024 | $44.99 | ||||
| 6 | ||||||
| 7 | ||||||
| 8 | ||||||
| 9 |
How to fix it
Wrap the catalog range in dollar signs to make it absolute. The dollar sign before a column letter locks the column; the dollar sign before a row number locks the row. With every part of the range locked, dragging the formula down no longer shifts anything. Every copy keeps pointing at the same catalog.
=VLOOKUP(D2,$A$2:$B$5,2,FALSE)- •
$A$2→ locked column A, locked row 2: anchors the top-left corner of the catalog - •
$B$5→ locked column B, locked row 5: anchors the bottom-right corner of the catalog - •
Drag from E2 down→ every row gets =VLOOKUP(D{row},$A$2:$B$5,2,FALSE), same range, different lookup value. All three return the right price. - •
F4 shortcut→ click into a reference and tap F4. Excel toggles between A2, $A$2, A$2, $A2
Where people go wrong
- Using TRUE instead of FALSE
You add TRUE at the end, or leave it blank (which defaults to TRUE), and your formula returns results that look almost right but are completely wrong. This is especially dangerous because Excel gives you no warning.
Fix: Always explicitly type FALSE as the fourth argument unless you specifically need approximate matching and your table is sorted ascending. - Forgetting $ signs when copying down
You write a perfect formula in row 2 and drag it down. By row 10 the results are wrong or showing #REF! errors. The table range shifted with each row.
Fix: Lock your table array with $ signs: =VLOOKUP(A2,$B:$D,3,FALSE). The $ makes those column references absolute. - Column index out of range
You specify col_index_num as 5 but your table_array only has 4 columns. Excel returns #REF! and you wonder why a formula that looks correct is failing.
Fix: Count the columns in your table_array carefully. If table_array is B:E that is 4 columns, so col_index_num cannot exceed 4. - Lookup value not in first column
You want to look up by employee name but names are in column C and IDs are in column A. VLOOKUP can only search the first column of your range. If you set range to C:E it searches column C, but then it can't return column A because that would mean looking left.
Fix: Restructure your data so the lookup column is first. Or switch to INDEX MATCH which can look in any direction.
Notes
- VLOOKUP is case-insensitive. "apple" and "APPLE" return the same result
- Wildcard characters (* and ?) work in lookup_value when range_lookup is FALSE
- For multiple matches VLOOKUP returns the first match only. It stops searching after the first hit
- VLOOKUP can handle up to 255 characters in the lookup_value argument
- Column index counting starts at 1, not 0
- In Excel 365 and Excel 2021 and later use XLOOKUP instead. It is more powerful and has no left-only limitation
- Approximate match (TRUE) requires the first column to be sorted ascending. Unsorted data returns wrong results silently
Now prove it
Reading about VLOOKUP is one thing.
Using it under pressure on real data, with a manager waiting and a deadline in 20 minutes, is completely different.
These exercises put you in real job scenarios where VLOOKUP is the only way out.
Here is the thing about VLOOKUP.
You can read this page twice and still freeze when your manager drops a 10,000-row spreadsheet on your desk and says the numbers are wrong.
That gap, between knowing what VLOOKUP does and being able to use it confidently when it actually matters, is exactly what CellSkill is built to close.
Not with more reading.
With practice on scenarios that look like your actual job.
Start practicing VLOOKUP for free →