Back to Blog
Lesson 22 of the PostgreSQL: SQL & PostgreSQL from Scratch course
DatabasesAugust 10, 20264 min read

Working with LEFT JOIN: Mastering Outer Joins in PostgreSQL

Master the LEFT JOIN in PostgreSQL. Learn to retrieve all records from a primary table even when matching rows in related tables are missing.

PostgreSQLSQLLEFT JOINOuter JoinsData retrievalDatabases
White jigsaw puzzle pieces on a vivid blue background from a top view, perfect for creative concepts.

Previously in this course, we explored Understanding INNER JOIN: Mastering Relational Queries in PostgreSQL to link tables that share matching values. While INNER JOIN is excellent for finding records with perfect pairs, it hides "orphan" records—data that exists in one table but lacks a counterpart in another.

In this lesson, we add the LEFT JOIN to your toolkit, allowing you to perform broader data retrieval by including all rows from your "left" (primary) table, regardless of whether a match exists in the "right" table.

Understanding LEFT JOIN from First Principles

In a relational database, a LEFT JOIN (a type of Outer Join) tells PostgreSQL: "Give me every row from the table on the left, and if you find a match in the table on the right, include that too."

If no match is found for a row on the left, PostgreSQL doesn't discard that row. Instead, it fills the columns from the right-hand table with NULL values. This is essential for reporting. For example, if you want a list of all customers, including those who have never placed an order, an INNER JOIN would silently exclude the inactive customers. A LEFT JOIN includes them, making the missing order data explicit as NULL.

LEFT JOIN vs INNER JOIN: A Quick Comparison

FeatureINNER JOINLEFT JOIN
Matching rowsIncludedIncluded
Unmatched left rowsDiscardedIncluded (with NULLs)
Unmatched right rowsDiscardedDiscarded
Use CaseStrict relationshipsReporting all primary entities

Worked Example: Finding Inactive Customers

Two women browsing clothes in a boutique, exploring fashion choices indoors.

Let’s apply this to our store project. We have a customers table and an orders table. We want to see a list of every customer and their order ID, even if they haven't bought anything yet.

SQL
SELECT 
    customers.name, 
    orders.id AS order_id
FROM customers
LEFT JOIN orders ON customers.id = orders.customer_id;

When you execute this, if customer_id 5 has no orders, the result will look like this:

nameorder_id
Alice101
BobNULL
Charlie102

The NULL in the order_id column is the database's way of signaling that there is no related record in the orders table for Bob.

Hands-on Exercise: Identifying Products without Sales

Building on our store schema, practice your data retrieval skills by identifying which products haven't sold yet.

  1. Write a query using LEFT JOIN between the products table and the order_items table.
  2. Select the product name and the order_id (or id from order_items).
  3. Observe how products with zero sales appear in your results with NULL values.

Common Pitfalls

  • Filtering out your own results: A common mistake is using a WHERE clause that filters the right-side table (e.g., WHERE orders.id > 100). If you filter on the right-side column, you effectively turn your LEFT JOIN back into an INNER JOIN because the NULL values created by the join fail the filter test. Always check your WHERE criteria if you notice records disappearing.
  • Assuming every join is an INNER JOIN: Never assume that the result set will contain as many rows as the right-side table. If you join a customers table to an orders table, you might end up with more rows than there are customers if one customer has multiple orders.
  • Confusing LEFT and RIGHT: While RIGHT JOIN exists, it is rarely used in professional environments. It is almost always cleaner to keep your primary table on the left and use LEFT JOIN to maintain consistent, readable code.

FAQ

Why does my LEFT JOIN return more rows than I expected? If a customer has placed three separate orders, the LEFT JOIN will create three rows for that customer (one for each order). If you only want to see the customer once, you would need to use aggregation, which we will cover in the next few lessons.

Is it possible to have multiple NULLs in the result? Yes. If you join multiple tables (e.g., Customers -> Orders -> Shipments), and a customer has no orders, the columns for both orders and shipments will be NULL.

What is the difference between LEFT JOIN and LEFT OUTER JOIN? None. In PostgreSQL, LEFT JOIN is shorthand for LEFT OUTER JOIN. They are functionally identical.

Recap

The LEFT JOIN is your primary tool for retrieving "everything from table A, plus what exists in table B." It prevents data loss by using NULL placeholders when relationships aren't met, which is invaluable for identifying gaps in your data. By understanding how these joins interact with WHERE clauses, you ensure your queries remain accurate and performant.

Up next: We will begin our exploration of Aggregate Functions, where we'll learn how to calculate totals and averages across your store's data.

Similar Posts