If SQL JOINs confuse you, read this
Hey - Tom here.
SQL JOINs trip up more beginners than any other concept I teach.
You write what seems like a perfectly reasonable query, then boom - either zero results when you know data exists, or millions of rows when you expected hundreds.
The problem isn't that JOINs are complex.
It's that most tutorials dive into technical details without explaining the fundamental decision that drives everything.
Today, I'm going to share my version.
Let's get into it.
In today's edition
- The one rule that tells you which join type to use
- Breaking down INNER JOIN vs LEFT JOIN
- A simple mental model that works for any scenario
- The performance trap that catches everyone out
The golden rule of SQL JOINS
Use INNER JOIN to filter your data.
Use LEFT JOIN to preserve your data.
Think about it like your Instagram feed.
Your "Following" tab shows posts only from accounts you follow (INNER JOIN - strict matching).
Your "Explore" tab shows your posts plus suggestions, even if you don't follow those accounts (LEFT JOIN - keep your stuff, add extras).
Let's say you're analysing customer data.
You have a customers table and an orders table.
Scenario 1: Monthly sales report
You want to see customers who actually bought something this month.
SELECT c.name, SUM(o.total) as monthly_spend FROM customers c INNER JOIN orders o ON c.customer_id = o.customer_id WHERE o.order_date >= '2025-01-01' GROUP BY c.name;
INNER JOIN filters. You only get customers with orders. Perfect for sales reports.
Scenario 2: Email marketing list
You want all customers, including those who haven't bought anything yet.
SELECT c.name, SUM(o.total) as monthly_spend FROM customers c INNER JOIN orders o ON c.customer_id = o.customer_id WHERE o.order_date >= '2025-01-01' GROUP BY c.name;
LEFT JOIN preserves. You get every customer, with NULL values for those who haven't ordered. Perfect for targeting non-buyers.
If you're unsure, start with LEFT JOIN.
You can always filter out the NULLs later.
Generic template you can adapt anywhere
SELECT main_table.main_cols, extra_table.additional_info FROM main_table LEFT JOIN extra_table ON main_table.id = extra_table.main_id;
The performance trap
Everyone thinks INNER JOIN is faster.
Sometimes it is, sometimes LEFT JOIN is faster.
The database optimiser is smarter than you think.
Focus on getting the right data first, then work it out.
TL;DR:
- INNER JOIN = filter to matched records only
- LEFT JOIN = keep all main records, add optional extras
- When in doubt, use LEFT JOIN - it's safer
The free issue ends here. Thanks for reading and have a great weekend!
Tom
If you want to turn these lessons into real skills, you should consider joining Premium.
What you get as a premium member:
- Code examples, datasets, guides, checklists, and much more!
- Full archive access to see all previous additions (and access the resources!)
- Personal insights and career advice from real-world experience
- £400+ in ready-to-use tools:
- Data Dictionary Builder (£99 value)
- Executive Data Storytelling Slide Deck (£149 value)
- Data Salary Negotiation Scripts (£199 value)
Premium gives you everything you need to practice, implement, and accelerate your career — not just theory.
What's included this week?
- 19 hands-on exercises with a real pizza shop database (Beginner → Expert progression)
- Real business scenarios: Customer segmentation, inventory optimisation, delivery performance
- SQL interview questions with detailed answers
- Complete reference guide for all JOIN types and advanced techniques
Your exclusive offer
Join as a Founding Member for 50% off your subscription for life (£9.50/m).
But this won't always be the price.
The Offer expires on 26/09/2025 — after that, the price doubles.
If you want to lock in the 50% off rate for life (and get access to all past & future resources), here's how to join:
- Click the button below
- Enter coupon code FOUNDERS and press apply at checkout
- Get instant access to all historic editions and this one (you'll see an option to log in on the web version of this newsletter)