A left outer join example SQL PostgreSQL guide helps you combine rows from two tables while keeping every record from the left table, even when no matching record exists in the right table. This makes LEFT JOIN especially useful for finding missing relationships, reporting incomplete data, and preserving a complete list of primary records Turns out it matters..
Introduction
PostgreSQL’s LEFT JOIN—also written as LEFT OUTER JOIN—returns all rows from the first, or left, table. In practice, it adds matching rows from the second, or right, table when the join condition is satisfied. If PostgreSQL cannot find a match, the result still contains the left-table row, with NULL values in the columns selected from the right table The details matter here..
This behavior distinguishes a left join from an INNER JOIN, which returns only rows having matches in both tables. A left join is therefore ideal when the existence of related data matters, but the absence of that data must not remove the original record from the result The details matter here..
Basic PostgreSQL LEFT JOIN Syntax
SELECT
left_table.column_1,
right_table.column_2
FROM left_table
LEFT JOIN right_table
ON left_table.id = right_table.left_table_id;
The keyword LEFT OUTER JOIN is fully interchangeable with the shorter LEFT JOIN:
FROM left_table
LEFT OUTER JOIN right_table
ON left_table.id = right_table.left_table_id;
PostgreSQL treats both forms identically. The OUTER keyword is optional and does not change the result.
The most important part of the query is the ON clause. Because of that, it defines how PostgreSQL determines whether two rows match. Although equality between primary-key and foreign-key columns is common, the condition can also use other comparison operators or multiple conditions.
Complete LEFT OUTER JOIN Example
Consider a database containing customers and orders. Every customer should appear in a report, including customers who have never placed an order.
Sample Tables
CREATE TABLE customers (
customer_id integer PRIMARY KEY,
customer_name text NOT NULL,
city text
);
CREATE TABLE orders (
order_id integer PRIMARY KEY,
customer_id integer,
order_total numeric(10, 2),
order_date date
);
Sample Data
INSERT INTO customers (customer_id, customer_name, city)
VALUES
(1, 'Amelia', 'London'),
(2, 'Benjamin', 'Paris'),
(3, 'Chloe', 'Berlin'),
(4, 'Daniel', 'Madrid');
INSERT INTO orders (order_id, customer_id, order_total, order_date)
VALUES
(101, 1, 45.Even so, 00, '2025-01-10'),
(102, 1, 72. Think about it: 50, '2025-01-18'),
(103, 2, 30. 00, '2025-01-12'),
(104, 4, 95.
Customer `3` has no corresponding order. An `INNER JOIN` would exclude that customer, but a left join preserves the record.
### Query
```sql
SELECT
c.customer_id,
c.customer_name,
c.city,
o.order_id,
o.order_total,
o.order_date
FROM customers AS c
LEFT JOIN orders AS o
ON c.customer_id = o.customer_id
ORDER BY c.customer_id, o.order_id;
Expected Result
| customer_id | customer_name | city | order_id | order_total | order_date |
|---|---|---|---|---|---|
| 1 | Amelia | London | 101 | 45.So 00 | 2025-01-10 |
| 1 | Amelia | London | 102 | 72. Now, 50 | 2025-01-18 |
| 2 | Benjamin | Paris | 103 | 30. 00 | 2025-01-12 |
| 3 | Chloe | Berlin | NULL | NULL | NULL |
| 4 | Daniel | Madrid | 104 | 95. |
Chloe remains in the result because customers is the left table. Since no order has customer_id = 3, PostgreSQL fills the selected order columns with NULL.
How PostgreSQL Processes the Join
Conceptually, PostgreSQL evaluates a left join in these stages:
- It selects one row from the left table.
- It searches the right table for rows satisfying the
ONcondition. - It creates one output row for every match.
- If no match exists, it creates one output row using values from the left table and
NULLvalues for right-table columns. - It repeats the process for every left-table row.
When a left-table row matches several right-table rows, it appears several times. This is why Amelia appears twice: she has two orders. A join does not automatically group or summarize related records.
PostgreSQL may choose different physical execution strategies, such as a hash join, nested-loop join, or merge join. Consider this: these internal choices generally do not alter the logical result. The database planner considers factors such as row counts, available indexes, statistics, and query conditions.
LEFT JOIN vs. INNER JOIN
An INNER JOIN keeps only matched pairs:
SELECT
c.customer_id,
c.customer_name,
o.order_id
FROM customers AS c
INNER JOIN orders AS o
ON c.customer_id = o.customer_id;
This query returns Amelia, Benjamin, and Daniel, but not Chloe But it adds up..
A LEFT JOIN keeps all customers:
SELECT
c.customer_id,
c.customer_name,
o.order_id
FROM customers AS c
LEFT JOIN orders AS o
ON c.customer_id = o.customer_id;
Use an inner join when unmatched records are irrelevant. Use a left join when the left table represents the complete population being analyzed.
Finding Records with No Match
A common use of `LEFT
Finding Records with No Match
A common use of LEFT JOIN is to identify records in the left table that have no corresponding entries in the right table. By adding a WHERE clause that checks for NULL values in the right table's key column, you can filter the results to show only unmatched records.
SELECT
c.customer_id,
c.customer_name,
c.city
FROM customers AS c
LEFT JOIN orders AS o
ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;
Result
| customer_id | customer_name | city |
|---|---|---|
| 3 | Chloe | Berlin |
This query returns only Chloe, the customer without any orders. The WHERE o.order_id IS NULL condition filters out all matched rows, leaving only those left-table records that had no matches in the right table Still holds up..
Performance Considerations
While LEFT JOIN is powerful, it can impact query performance, especially with large datasets. PostgreSQL's query planner typically handles joins efficiently, but consider these optimization strategies:
- Indexing: Ensure foreign key columns used in join conditions are indexed.
- Filter early: Apply
WHEREconditions before joining when possible to reduce the number of rows processed. - Avoid unnecessary columns: Only select columns you need to minimize memory usage.
Conclusion
The LEFT JOIN is an essential SQL operation for retrieving complete data from one table while optionally including related information from another. This makes it invaluable for scenarios where you need to maintain a complete list of entities regardless of whether they have associated data. Unlike INNER JOIN, it preserves all records from the left table, filling unmatched columns with NULL values. By understanding how PostgreSQL processes left joins and leveraging them with appropriate filtering conditions, you can write more effective and comprehensive database queries.