Skip to content
Aabha AI Academy

Stage 5 · L21

Explain inner, left, right and full joins with actual rows

Core · original Session 5

Native checkpoint 05

Download starter

Use the starter for this stage's focused examples. The cumulative transfer and solution belong at the stage-end capstone. Baseline checks pass; transfer checks initially fail. Downloads contain the matching native starter and solution for this stage.

A join combines related stored rows according to a condition. Rental.equipment_id equals Equipment.id is the relationship used here. An inner join excludes a rental without a matching item; a left outer join retains the left row with nulls on the right. The implemented non-null foreign key prevents orphaned rental item references, but outer joins can still be useful for optional relations and reporting.

A foreign key constrains stored references; an ORM relationship supplies navigation; a join specifies a query shape. They are three different responsibilities. Do not assume that declaring a relationship means all rows are automatically loaded or that a join selects the fields required by a public response.

The nested rental representation includes equipment details. list_rentals deliberately uses joinedload(Rental.equipment), which joins and populates the many-to-one relationship in one statement. It then constructs RentalDetail while the session is owned. This is different from writing a join only to filter rows while leaving a relationship unloaded.

When joining a one-to-many collection, one parent can appear in several SQL rows. Limiting raw joined rows can truncate a parent's children or change parent-page membership. This checkpoint loads only a many-to-one item from each rental, so each rental contributes one item. For collection responses choose a parent-page query and a deliberate second select-in load, rather than treating all join shapes as interchangeable.

RIGHT JOIN retains every right-side row and supplies nulls for missing left matches; reversing the tables in a LEFT JOIN expresses the same retention. FULL OUTER JOIN retains unmatched rows from both sides. join_examples.py uses two VALUES relations requested{1,2} and stocked{2,3}: RIGHT gives(2,2)/(null,3); FULL also includes(1,null). These are actual PostgreSQL query exercises, not new inventory tables or orphaned rental rows. The application foreign keys still prevent missing referenced equipment.

The focused SQL uses WITH to name two temporary query relations, each populated by VALUES. USING(id) compares their id columns. NULL marks the absent side of an unmatched pair; it is not a fabricated matching value. COALESCE(r.id,s.id) chooses the non-null key for readable ordering. These small row sets let you calculate every join result before running PostgreSQL; no state update, lock or pagination is part of this lesson.

INNER: only matched rows; LEFT: every left row; RIGHT: every right row; FULL: matched plus unmatched rows from both sides
INNER: only matched rows; LEFT: every left row; RIGHT: every right row; FULL: matched plus unmatched rows from both sides

Follow the running code

Focused lesson example; see the end-of-stage capstone for the cumulative app · stage 05

WITH requested(id) AS (VALUES (1),(2)), stocked(id) AS (VALUES (2),(3))
SELECT r.id AS requested_id, s.id AS stocked_id
FROM requested r FULL OUTER JOIN stocked s USING(id)
ORDER BY COALESCE(r.id,s.id);

Predict and observe this focused example using the concepts explained above. Its boundary is stated in the focused answer.

Guided lab

  1. Read the explanation and predict the focused example’s outcome.
  2. Write the inner, left, right and full result pairs for requested={1,2}, stocked={2,3}. Do not add pagination, mutation or locks.
  3. Compare the observed outcome with the focused answer and state its boundary.

Expected: Inner: (2,2). Left: (1,NULL),(2,2). Right: (2,2),(NULL,3). Full: all three pairs. The preserved side determines unmatched rows. This is an actual PostgreSQL VALUES join exercise; it changes no rental state and needs no later capacity policy.

  • An inner join omits unmatched rows; outer joins retain the chosen side and fill missing-side columns with NULL.

Focused exercise and answer

Complete this focused exercise before reading its answer. The full native transfer is introduced only at the end of the stage.

Your transfer task: Write the inner, left, right and full result pairs for requested={1,2}, stocked={2,3}. Do not add pagination, mutation or locks.

  1. Write the inner, left, right and full result pairs for requested={1,2}, stocked={2,3}. Do not add pagination, mutation or locks.
Inspect the matching answer

This answer addresses the focused exercise above; the cumulative implementation is shown only after the stage prerequisites.

Inner: (2,2). Left: (1,NULL),(2,2). Right: (2,2),(NULL,3). Full: all three pairs. The preserved side determines unmatched rows. This is an actual PostgreSQL VALUES join exercise; it changes no rental state and needs no later capacity policy.

Check your reasoning

Which join keeps unmatched rows from both sides?

Show the explanation

FULL OUTER JOIN keeps every unmatched left and right row as well as matches. NULL marks values absent from the opposite side.

Reading progress

54 lessons remain open to guests. Marking a lesson read records reading only; it does not award assessment credit or a certificate.

Device reading marks require browser storage. Reading is always available.

Sign in or create an account to save separate account progress. Your current page is kept.