SQL Joins Explained With Examples
SkillVeris Team
Data Science Team

A SQL join combines rows from two or more tables based on a related column, letting you query data spread across a normalized database.
In this guide, you'll learn:
- INNER JOIN returns only matching rows; LEFT JOIN keeps all rows from the left table and fills unmatched right-side columns with NULL.
- RIGHT JOIN is the mirror of LEFT JOIN, and FULL OUTER JOIN keeps unmatched rows from both tables.
- The ON clause defines how rows match, usually a foreign key equal to a primary key.
- A missing or wrong join condition causes a CROSS JOIN, multiplying rows into an accidental explosion.
1What Is a SQL Join?
A SQL join is a clause that combines rows from two or more tables based on a related column between them, letting you assemble a complete picture from data that lives in separate tables. For example, if orders live in one table and customers in another, a join lets you list every order alongside the customer's name in a single query.
Joins exist because relational databases store data in normalized tables to avoid duplication. The join is how you stitch that data back together at query time. Mastering the four main join types — INNER, LEFT, RIGHT, and FULL — covers nearly every real-world need.
2Example Tables
To make the examples concrete, imagine two small tables. A customers table holds one row per customer, and an orders table holds one row per order with a customer_id linking back to the customer who placed it.
The customer_id in orders is a foreign key pointing to the id in customers. This relationship is what every join below uses to match rows.
- customers: id, name # e.g. (1, 'Ada'), (2, 'Grace'), (3, 'Alan')
- orders: id, customer_id, total # e.g. (10, 1, 50), (11, 1, 20), (12, 2, 99)
- Customer 3 (Alan) has no orders.
- Every order points to a real customer via customer_id.
3INNER JOIN: Only Matches
An INNER JOIN returns only the rows that have a match in both tables. If a customer has no orders, or an order has no matching customer, that row is excluded. It answers the question: which records exist on both sides?
In the example, an inner join of customers and orders returns Ada's two orders and Grace's one order. Alan disappears entirely because he has no orders. This is the most common join and the default when people say just join.
- SELECT c.name, o.total
- FROM customers c
- INNER JOIN orders o ON c.id = o.customer_id;
- # Returns Ada (50), Ada (20), Grace (99). Alan is excluded.
4LEFT JOIN: Keep the Left Side
A LEFT JOIN returns all rows from the left table and the matching rows from the right table. Where there is no match, the right-side columns come back as NULL. It answers: give me everything on the left, with related data where it exists.
Running a left join from customers to orders returns Alan too, but with a NULL total because he has no orders. Left joins are essential for finding records that lack a relationship, such as customers who never ordered.
💡Finding Missing Matches
To find rows with no match, add WHERE o.customer_id IS NULL after a LEFT JOIN. This is the standard pattern for questions like which customers have never placed an order.
5RIGHT and FULL OUTER Joins
A RIGHT JOIN is simply the mirror image of a LEFT JOIN: it keeps all rows from the right table and fills unmatched left-side columns with NULL. In practice most developers just reorder the tables and use LEFT JOIN, which reads more naturally, so RIGHT JOIN is rare.
A FULL OUTER JOIN keeps unmatched rows from both tables at once, filling gaps with NULL on either side. It is useful for reconciliation — for instance, comparing two systems to find records that exist in one but not the other.
Support Caveat
Not every database supports FULL OUTER JOIN. MySQL historically did not, so developers emulate it by combining a LEFT JOIN and a RIGHT JOIN with UNION. PostgreSQL, SQL Server, and Oracle support it directly.
6The ON Clause and Join Conditions
The ON clause defines how rows from the two tables match. Most joins match a foreign key to a primary key with equality, such as ON c.id = o.customer_id. You can join on multiple columns or use non-equality conditions, though equality on indexed keys is by far the most common and fastest.
Confusing the ON clause with the WHERE clause changes results in outer joins. A condition in ON filters before the join completes; the same condition in WHERE filters after, which can silently turn a LEFT JOIN back into an INNER JOIN by removing the NULL rows.
7Common Mistakes to Avoid
Joins are powerful but easy to get subtly wrong. These mistakes produce either wrong numbers or slow queries.
- Forgetting the ON clause, which produces a CROSS JOIN that multiplies every row against every other.
- Putting an outer-table filter in WHERE instead of ON, which drops the NULL rows and cancels the outer join.
- Joining on unindexed columns, forcing slow full-table scans.
- Assuming a join is one-to-one when it is one-to-many, which duplicates left-side rows and inflates SUM and COUNT.
- Using SELECT * across joined tables, returning duplicate id columns and ambiguous names.
⚠️The Accidental Explosion
A one-to-many join duplicates rows on the one side. If you then SUM a value from that side, the total is inflated. Aggregate in a subquery first, or use COUNT(DISTINCT ...) to be safe.
8Key Takeaways
Joins become intuitive once you picture which rows each type keeps.
- INNER JOIN keeps only rows matching in both tables.
- LEFT JOIN keeps all left rows, NULL-filling unmatched right columns.
- RIGHT JOIN mirrors LEFT; FULL OUTER JOIN keeps unmatched rows from both sides.
- The ON clause defines the match; keep outer-table filters in ON, not WHERE.
- Index your join columns and watch for one-to-many row inflation.
9Frequently Asked Questions
Q: What is the difference between INNER JOIN and LEFT JOIN? A: INNER JOIN returns only rows that match in both tables, while LEFT JOIN returns all rows from the left table plus matches from the right, filling unmatched right-side columns with NULL. Use LEFT JOIN when you need to keep records that may lack a related row.
Q: Why is my join returning too many rows? A: This usually happens when the join is one-to-many but you expected one-to-one, so each left row is duplicated for every match on the right. Check the relationship, and if you are aggregating, use a subquery or COUNT(DISTINCT ...) to avoid inflated totals.
Q: What is a CROSS JOIN? A: A CROSS JOIN pairs every row of one table with every row of the other, producing the Cartesian product. It is occasionally intentional, but far more often it is an accident caused by forgetting the ON clause or join condition.
Q: Should I use RIGHT JOIN? A: You rarely need to. A RIGHT JOIN is just a LEFT JOIN with the tables reversed, and most developers find LEFT JOIN easier to read, so they simply reorder the tables. Use whichever makes the query clearer to you and your team.
Related Reading
Get The Print Version
Download a PDF of this article for offline reading.
About the Publisher
SkillVeris Team
Data Science Team
Our data team shares real-world analytics, ML, and SQL insights grounded in industry practice.
View all postsRelated Posts
Never miss an update
Get the latest tutorials and guides delivered to your inbox.
No spam. Unsubscribe anytime.