LEFT JOIN: Keeping Rows That Don't Match
Use LEFT JOIN to list every movie alongside its audience rating, including movies that have never been rated.
Overview
A LEFT JOIN returns every row from the left (first) table, and the matching
row(s) from the right table when one exists, or NULL in every right-table
column when it doesn't. This is the tool you reach for whenever "no match"
is itself meaningful information, rather than something you want to discard.
A classic case: not every movie in a catalog has been rated by every source.
An INNER JOIN between movies and ratings would silently hide movies
with no rating at all. A LEFT JOIN keeps them in the result, with NULL
standing in for "we don't have that rating."
The Query
Step-by-Step Breakdown
FROM movies m: the left table. Every row from here is guaranteed to appear in the output at least once.LEFT JOIN ratings r ON m.id = r.movie_id AND r.source = 'Audience': attach the matchingratingsrow, but only the one wheresource = 'Audience'. Notice the source filter lives inside theONclause, not in aWHEREclause: that distinction matters for outer joins (see Common Mistakes).SELECT m.title, m.genre, r.score AS audience_score: if no audience rating exists for a movie,r.score(and every otherratingscolumn) comes back asNULLfor that row, but the movie row itself is still included.ORDER BY m.title: alphabetical for readability.
Several movies in this dataset only have a "Critics" rating and no
"Audience" rating: those rows will show NULL for audience_score instead
of disappearing.
Variations
Find exactly which movies have no audience rating, using the "anti-join" pattern:
This is a common and useful idiom: do a LEFT JOIN, then filter with
WHERE <right_table>.<any_not_null_column> IS NULL to isolate rows that
didn't find a match. It effectively answers "which movies exist that
ratings doesn't have an audience score for?"
ON vs. WHERE changes the meaning
If you moved r.source = 'Audience' out of the ON clause and into a
WHERE clause instead, the query would stop behaving like a left join.
WHERE runs after the join, so it would filter out every row where
r.source isn't 'Audience', including the NULL rows for movies with
no rating at all, silently turning your left join back into something
closer to an inner join.
Common Mistakes
- Putting join-specific filters in
WHEREinstead ofON. As shown above, this quietly discards the unmatched rows aLEFT JOINwas meant to preserve. - Checking the wrong column for
NULL. Use a column from the right table that can never beNULLwhen a match does exist, typically its primary key (r.id), not an arbitrary column that might legitimately beNULL. - Forgetting which table is "left."
A LEFT JOIN Bkeeps all ofA; swapping the table order changes the result. If you want all rows fromratingsinstead, either reorder the join or useRIGHT JOIN. - Expecting aggregate functions to ignore the extra NULL rows.
COUNT(*)over a left-joined result counts every row, including the ones withNULLin every right-table column. UseCOUNT(r.id)if you want to count only actual matches.
Cite this resource
SQLSimplified. "LEFT JOIN: Keeping Rows That Don't Match Example". Available at: https://sqlsimplified.online/examples/left-join