Tabellab
Excel formulas

SQL JOIN explained with Excel: INNER JOIN and LEFT JOIN side by side

If you have used VLOOKUP or XLOOKUP, you already know what a SQL JOIN does: it matches rows of two tables on a shared key and brings columns across. The difference is what happens to rows without a match. A LEFT JOIN keeps every row of the left table and fills the missing columns with NULL, like a lookup that returns #N/A. An INNER JOIN keeps only the rows that matched. In the example below, six orders join to four customers: the LEFT JOIN returns 6 rows and 720 in revenue, the INNER JOIN only 4 rows and 530, because two orders point to customers that do not exist.

Updated 20 Oct 2026 5 min read By Tabellab team

The SQL query and its spreadsheet twin

The query SELECT o.order_id, o.amount, c.name FROM orders o LEFT JOIN customers c ON o.customer_id = c.customer_id walks through every order, looks up its customer_id in the customers table and adds the name. In Excel that is one lookup per row:

=XLOOKUP(B2,$G$2:$G$5,$H$2:$H$5,"Unknown")

The ON clause is the lookup key (B2 against G2:G5), the selected column c.name is the return range H2:H5, and the left table is simply the table you write the formula in. With VLOOKUP the same join is =IFNA(VLOOKUP(B2,$G$2:$H$5,2,FALSE),"Unknown"). The FALSE matters: a join is an exact match.

INNER JOIN: only the rows where the lookup succeeds

An INNER JOIN drops every order whose customer is missing. In a spreadsheet, flag the rows that would survive with =IF(ISNUMBER(MATCH(B2,$G$2:$G$5,0)),1,0) and use the flag in your totals: =SUM(E2:E7) counts the joined rows and =SUMPRODUCT(C2:C7,E2:E7) adds up their revenue.

This is why an INNER JOIN can quietly lose money from a report. Orders 1004 and 1006 (190 in revenue) belong to customer ids C07 and C09, which are not in the customer table. In SQL they simply disappear from the result, with no error. In Excel you at least see the #N/A.

Worked example: six orders joined to four customers

Orders (A:C) and customers (G:H) are yellow inputs. Column D is the LEFT JOIN, column E flags the rows an INNER JOIN keeps, and the totals compare both.

Worked example: six orders joined to four customers
ABCDEFGH
1order_idcustomer_idamountLEFT JOIN: nameIn INNER JOIN?customer_idname
21,001C01120Bluebird Café1C01Bluebird Café
31,002C0375Pine Street Bakery1C02Northside Deli
41,003C02240Northside Deli1C03Pine Street Bakery
51,004C0760Unknown0C04Harbor Hotel
61,005C0195Bluebird Café1
71,006C09130Unknown0
8
9Rows in the LEFT JOIN (every order)6
10Rows in the INNER JOIN (matched orders)4
11Revenue in the INNER JOIN530
12Revenue in the LEFT JOIN720
13Orphan orders (name = Unknown)2
14Customers without any order (anti join)1
Key formulas
  • D2=XLOOKUP(B2,$G$2:$G$5,$H$2:$H$5,"Unknown")LEFT JOIN with a label for NULL
  • E2=IF(ISNUMBER(MATCH(B2,$G$2:$G$5,0)),1,0)1 if the row survives an INNER JOIN
  • E10=SUM(E2:E7)Rows in the INNER JOIN
  • E11=SUMPRODUCT(C2:C7,E2:E7)Revenue in the INNER JOIN
  • E13=COUNTIF(D2:D7,"Unknown")Orphan orders
  • E14=SUMPRODUCT(--(COUNTIF(B2:B7,G2:G5)=0))Customers without orders (anti join)

Invented orders and customers. The same logic works with VLOOKUP and IFNA in older Excel versions and in Google Sheets.

LEFT JOIN and NULL: keep every row, label the gaps

A LEFT JOIN keeps all six orders. Where no customer matches, SQL returns NULL in the customer columns, the equivalent of #N/A from a lookup. In reports, replace it with a label: COALESCE(c.name, 'Unknown') in SQL, the fourth argument of XLOOKUP or IFNA(…,"Unknown") in Excel. Counting the label, =COUNTIF(D2:D7,"Unknown"), tells you how many orphan rows the data has.

Use a LEFT JOIN whenever the left table is the thing you are counting, such as all orders or all employees, and an INNER JOIN only when unmatched rows really should be excluded.

Finding unmatched rows in both directions

Data checks often need the rows that did not join. Orders without a customer: LEFT JOIN … WHERE c.customer_id IS NULL, in Excel the rows labelled Unknown. Customers without any order (an anti join): in Excel, =SUMPRODUCT(--(COUNTIF(B2:B7,G2:G5)=0)) counts the customers whose id never appears in the orders, here one, Harbor Hotel.

RIGHT JOIN is a LEFT JOIN with the tables swapped, and FULL OUTER JOIN keeps unmatched rows from both sides. In a spreadsheet you build those by running the lookup from the other table as well.

The duplicate-key trap

Lookups and joins behave differently when the key is not unique. XLOOKUP and VLOOKUP return the first match only. A SQL JOIN returns every match, so if customer C01 appears twice in the customer table, each C01 order appears twice in the result and the revenue is double-counted.

Before you trust a join, check that the key is unique on the lookup side: =COUNTIF($G$2:$G$5,G2) must be 1 for every customer, or in SQL SELECT customer_id, COUNT(*) FROM customers GROUP BY customer_id HAVING COUNT(*) > 1 must return nothing.

Common mistakes

  • Using an INNER JOIN by default. It silently drops unmatched rows, and totals shrink without an error.
  • Approximate matching. A VLOOKUP without FALSE as the last argument is not a join and can return the wrong customer.
  • Duplicate keys on the lookup side. SQL repeats rows and double-counts, while a lookup hides the duplicate. Check uniqueness first.
  • Mixed key formats. "C01" and "C01 " or 1001 as text and as a number do not match. Clean keys with TRIM and consistent types.
  • Filtering the right table in WHERE. WHERE c.segment = 'Retail' after a LEFT JOIN removes the NULL rows and turns it into an INNER JOIN. Put the condition in the ON clause.
  • Ignoring the orphans. Rows labelled Unknown usually point to a data problem worth fixing at the source.

Frequently asked questions

Is VLOOKUP the same as a SQL join?

An exact-match VLOOKUP or XLOOKUP behaves like a LEFT JOIN that returns one column: every row of your table is kept and #N/A appears where SQL would return NULL. The difference is duplicates: a lookup returns the first match, a join returns all of them.

What is the difference between an INNER JOIN and a LEFT JOIN?

An INNER JOIN returns only rows that have a match in both tables. A LEFT JOIN returns every row of the left table and fills the columns from the right table with NULL where there is no match.

How do I find rows that do not match in Excel?

Look up the key with MATCH or XLOOKUP and count the failures, for example with ISNA or an "Unknown" label. To find keys in the second table that never appear in the first, use COUNTIF(first range, key) = 0.

Can I learn SQL concepts without a database?

Yes. WHERE, GROUP BY, HAVING, joins and CASE WHEN all have spreadsheet equivalents such as COUNTIFS, SUMIFS, XLOOKUP and IFS. Building the result by hand shows exactly what each clause does before you write it in SQL.

Practise it in a lab

Related guides

Reading is step one. Doing is step two.

Every guide links to a lab where you build the same calculation in an online spreadsheet and get instant feedback.

Open the lab