Dataslope logoDataslope

Understanding Joins

The big picture of combining tables — what a join actually does, why it matches rows on a condition, and how to picture the result before writing one.

A join combines rows from two tables into a single result by matching them on a condition — almost always a foreign key meeting the primary key it points to. Joins are how the relational model delivers on its promise: data split for storage, recombined for answers. This page builds the intuition; the next two cover the specific kinds.

The question a join answers

You have customers in one table and orders in another. Neither table alone can answer "show each order with its customer's name." The name is in customers; the amount is in orders. A join stitches them together:

For each order, the database finds the customer whose id equals the order's customer_id, and glues their columns together into one wide row.

The anatomy of a JOIN

A join lives in the FROM part of a query. It names a second table and the matching condition with ON:

SQL
PostgreSQL 17

Read it: "From orders, joined to customers wherever the order's customer_id equals the customer's id, give me the order id, the customer name, and the amount." The ON clause is the heart — it states which rows belong together.

Table aliases keep joins readable

Writing orders. and customers. everywhere is tedious. SQL lets you give each table a short alias right after its name, then use the alias as a prefix:

SQL
PostgreSQL 17

orders o means "call orders o here." This is the style you will see in nearly all real SQL, because joins of three or four tables would be unreadable otherwise.

Why prefix columns at all?

Both tables might have a column named id. Writing o.id versus c.id removes the ambiguity — it tells the database (and the reader) which table's id you mean. When a column name exists in only one table, the prefix is optional, but using it consistently keeps joins clear.

A join is a matching process

Picture a join as checking every possible pairing of rows and keeping the ones where the ON condition is true:

You do not literally write that loop — remember, SQL is declarative. You describe the match with ON, and the database finds an efficient way to perform it. But this "keep the matching pairs" picture is exactly what a join means.

What comes next

There is one more crucial question: what about rows that have no match? An order with a missing customer, or a customer with no orders — do they appear or vanish? The answer depends on the kind of join, and that is precisely what the next two pages, Inner Joins and Outer Joins, are about.

Check your understanding

QuestionSelect one

What does a join do?

It deletes rows that appear in two tables.

It combines rows from two tables into one result by matching them on a condition.

It sorts a single table by two columns.

It copies one table on top of another.

QuestionSelect one

In JOIN customers c ON o.customer_id = c.id, what is the role of the ON clause?

It chooses which columns appear in the output.

It states the condition for matching rows between the two tables.

It sorts the combined result.

It limits how many rows are returned.

QuestionSelect one

Why are table aliases like orders o and customers c commonly used in joins?

They make the query run on more tables at once.

They give each table a short prefix, making column references shorter and removing ambiguity when both tables share a column name.

They permanently rename the tables in the database.

They are required for every single query.

On this page