Skip to content
/Chapter 5 · Joins
Lesson 5.3·garden_shop
Lesson 5.3

INNER JOIN vs LEFT JOIN in SQL

INNER JOIN keeps matches only. LEFT JOIN keeps every row from the left table.

An INNER JOIN returns only rows with a match on both sides. That is often what you want, but it hides rows that have no related record.

A LEFT JOIN keeps every row from the left table. Missing matches from the right table appear as NULL.

INNER JOIN vs LEFT JOIN at a glance

Join typeRows it keepsUse it when
INNER JOINOnly rows that match in both tables.You only want records with a related row.
LEFT JOINEvery row from the left table, plus matching rows from the right table. Missing right-side values become NULL.You need to keep unmatched left rows, such as customers with no orders.
Pattern
select left_table.id, count(right_table.id) as match_count
from left_table
left join right_table
  on left_table.id = right_table.left_id
group by left_table.id
Ready to run it?

Open the DuckDB playground with the matching dataset and query already filled in.

A concrete example

In the Garden Shop data, some customers have orders and some do not. AnINNER JOIN between customers andorders drops customers with no orders because there is no matching order row to return.

INNER JOIN: customers with orders only
select c.customer_id,
       c.first_name,
       o.order_id
from customers c
inner join orders o
  on o.customer_id = c.customer_id
order by c.customer_id, o.order_id

A LEFT JOIN starts from customers and keeps every customer. If a customer has no matching order, the order columns areNULL.

LEFT JOIN: every customer stays
select c.customer_id,
       c.first_name,
       o.order_id
from customers c
left join orders o
  on o.customer_id = c.customer_id
order by c.customer_id, o.order_id

Choose based on missing matches

Start with the question you are answering. If you only care about customers who placed orders, an inner join is fine. If you need every customer, including customers with no orders, put customers on the left and use a LEFT JOIN.

Count carefully after a left join. count(*) counts the kept left row even when the right side is missing; count(o.order_id) counts only matched orders, which is why no-order customers show 0.

Common JOIN gotchas

Schema · Garden ShopTable · customers9 columns · 20 rows
Table · customers

One row per customer. Some customers have no phone on file.

9 columns · 20 rows
customer_id intfirst_name textlast_name textemail textphone textcity textstate textsignup_date dateis_active bool
Your task

Return every customer with their totalorder count. Include customers who have placed no orders, sorted so customers with no orders appear first.

SQL Workbench
query.sqlgarden_shop · SQL engine loading
⌘↵ to run
·
Expected answer
  • Columns: customer_id, first_name, last_name, order_count.
  • Rows: 20 customers.
  • Four customers should have order_count 0: Liam, Emma, Chloe, and Daniel.