SQL JOINs Explained: How to Combine Data from Multiple Tables

Learn how SQL JOINs work and when to use INNER, LEFT, RIGHT and FULL joins to combine data from related database tables.

Share on Linkedin Share on WhatsApp

Estimated reading time: 5 minutes

Article image SQL JOINs Explained: How to Combine Data from Multiple Tables

In a relational database, information is rarely stored in a single place. Customers live in one table, their orders in another, and the products they buy in yet another. To answer a simple question like “which customers ordered which products,” you need a way to bring these tables together. That is exactly what SQL JOINs do.

Understanding joins is one of the most valuable skills for anyone working with data. In this article, we will break down how joins work and explore the main types with clear, practical examples.

Why do we split data into separate tables?

Relational databases are designed to avoid repeating the same information over and over. Instead of writing a customer’s full name and address on every single order, we store the customer once and link each order to that customer through an identifier, usually called a key.

  • A primary key uniquely identifies each row in a table (for example, a customer ID).
  • A foreign key is a column in one table that points to the primary key of another table.

Joins use these keys to match rows from different tables and present them as if they belonged to a single result.

The basic structure of a JOIN

Most joins follow the same simple pattern: you tell the database which two tables to combine and on which columns they should match.

SELECT customers.name, orders.total
FROM customers
JOIN orders
  ON customers.id = orders.customer_id;

Here, the database looks at each row in customers and finds the matching rows in orders where the IDs line up. The result is a combined table showing customer names next to their order totals.

The main types of JOINs

The difference between join types comes down to one question: what should happen to rows that do not have a match in the other table?

INNER JOIN

An INNER JOIN returns only the rows that have a match in both tables. If a customer has no orders, they simply will not appear in the result. This is the most common join and a good default when you only care about records that are connected.

LEFT JOIN

A LEFT JOIN returns all rows from the left (first) table, plus any matching rows from the right table. When there is no match, the columns from the right table are filled with empty values (NULL). This is perfect for questions like “list all customers, including those who have never placed an order.”

RIGHT JOIN

A RIGHT JOIN is the mirror image of a LEFT JOIN: it keeps all rows from the right table and fills in NULLs where the left table has no match. In practice, many developers simply rewrite these as LEFT JOINs by swapping the table order, but it is useful to know both exist.

FULL JOIN

A FULL JOIN (also called FULL OUTER JOIN) returns all rows from both tables, matching them where possible and using NULLs where there is no match on either side. It is helpful when you want a complete picture that includes unmatched records from both tables.

A quick comparison

Join typeKeeps unmatched left rows?Keeps unmatched right rows?
INNER JOINNoNo
LEFT JOINYesNo
RIGHT JOINNoYes
FULL JOINYesYes

Common mistakes to avoid

  • Forgetting the ON condition: without it, the database may combine every row with every other row, producing a huge and meaningless result.
  • Joining on the wrong columns: always make sure you are matching a foreign key to the correct primary key.
  • Ignoring NULLs: outer joins introduce empty values, so remember to handle them when filtering or calculating totals.

Putting it into practice

Joins become intuitive once you experiment with them. Try creating two small tables, filling them with a few rows, and running each type of join to see how the results change. Pay attention to which rows appear and which disappear, and you will quickly build a mental model of how the data connects.

If you want to deepen your understanding of databases and SQL, explore the free database and programming courses available on Cursa. They offer hands-on lessons that take you from writing your first query to designing complete data models.

NTFS, exFAT, FAT32 and APFS: Choosing the Right File System for a Drive

Understand what a file system does and how NTFS, exFAT, FAT32, APFS and ext4 differ, so you can format drives without losing compatibility.

Text Encoding Explained: ASCII, Unicode and Why You Sometimes See Strange Symbols

Learn how computers store text, what ASCII and Unicode actually are, why UTF-8 became the standard, and how to fix files that display garbled characters.

Idempotency in APIs: Why Retrying a Request Should Be Safe

Learn what idempotency means in backend development, which HTTP methods provide it, and how idempotency keys prevent duplicate operations.

What Is a CDN? How Content Delivery Networks Make Websites Fast

Learn what a CDN is, how edge caching and cache headers work, what a cache hit means, and when a CDN helps — or does not.

Semantic Versioning Explained: What a Number Like 2.4.1 Actually Tells You

MAJOR.MINOR.PATCH is a promise, not decoration. Learn to read version numbers and understand dependency range symbols.

What Is a Virtual Machine? Virtualization Explained for Beginners

Learn what a virtual machine is, how hypervisors work, how VMs differ from containers, and when to use each one.

How HTTPS Works: Certificates, the TLS Handshake and What the Padlock Really Means

A beginner-friendly walkthrough of HTTPS: what TLS certificates prove, how the handshake works, and what the browser padlock does not guarantee.

Big O Notation Explained: How to Talk About Code Efficiency

A beginner-friendly guide to Big O notation: what it measures, the most common complexity classes, and how to reason about the cost of your code.