Skip to content
Laviyx Learn

Try

SQL course menu

SQL FULL OUTER JOIN: Keep All Rows From Both Tables

Learn SQL FULL OUTER JOIN with diagrams and examples: keep matched and unmatched rows from both tables, find mismatches on either side, and emulate FULL JOIN in MySQL with UNION.

Intermediate6 min readUpdated
On this page

A FULL OUTER JOIN keeps every row from both tables. Rows that match are combined; rows without a partner on either side still appear, with NULLs for the missing side. It is the join for comparing two lists and seeing everything: matches, and mismatches in both directions.

FULL OUTER JOIN of customers and orders: Every row from both tables, matched where possible.customersorders
FULL OUTER JOINEvery row from both tables, matched where possible

The example tables#

customers

customer_idnamecity
1AshaMumbai
2RaviDelhi
3MeeraPune
4JohnChennai

orders

order_idcustomer_idamount
1011250
1021120
1032560
104590

Syntax#

SQL
SELECT columns
FROM table_a
FULL OUTER JOIN table_b
  ON table_a.column = table_b.column;

FULL JOIN is a shorter way to write the same thing.

Example#

SQLRun
SELECT c.name, o.order_id, o.amount
FROM customers c
FULL OUTER JOIN orders o
  ON o.customer_id = c.customer_id;
Output
name  | order_id | amount
------+----------+-------
Asha  | 101      | 250
Asha  | 102      | 120
Ravi  | 103      | 560
Meera | NULL     | NULL
John  | NULL     | NULL
NULL  | 104      | 90

The result contains three kinds of rows:

RowsWhy
Asha ×2, Ravimatched pairs (what an INNER JOIN returns)
Meera, Johncustomers without orders (what a LEFT JOIN adds)
order 104an order without a customer (what a RIGHT JOIN adds)

In other words, FULL OUTER JOIN = INNER JOIN + unmatched left rows + unmatched right rows.

Find mismatches on both sides#

Keep only rows where one side is missing. This is a classic reconciliation query, for example comparing a bank statement with your own records:

SQLRun
SELECT c.customer_id, c.name, o.order_id, o.customer_id AS order_customer
FROM customers c
FULL OUTER JOIN orders o
  ON o.customer_id = c.customer_id
WHERE c.customer_id IS NULL
   OR o.order_id IS NULL;
Output
customer_id | name  | order_id | order_customer
------------+-------+----------+---------------
3           | Meera | NULL     | NULL
4           | John  | NULL     | NULL
NULL        | NULL  | 104      | 5

Summarising with a FULL JOIN#

Because unmatched rows have NULLs, combine COALESCE with aggregates to produce a clean report:

SQLRun
SELECT COALESCE(c.name, 'Unknown customer') AS customer,
       COALESCE(SUM(o.amount), 0) AS total
FROM customers c
FULL OUTER JOIN orders o
  ON o.customer_id = c.customer_id
GROUP BY c.customer_id, c.name
ORDER BY total DESC;
Output
customer         | total
-----------------+------
Ravi             | 560
Asha             | 370
Unknown customer | 90
Meera            | 0
John             | 0

Every customer and every order is accounted for, and the totals add up to all revenue (1,020).

MySQL: emulate FULL OUTER JOIN#

MySQL does not support FULL OUTER JOIN. Combine a LEFT JOIN and a RIGHT JOIN with UNION, which also removes the duplicate matched rows:

SQLRun
SELECT c.name, o.order_id
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.customer_id
UNION
SELECT c.name, o.order_id
FROM customers c
RIGHT JOIN orders o ON o.customer_id = c.customer_id;

PostgreSQL, SQL Server, Oracle and SQLite 3.39+ support FULL OUTER JOIN directly.

Common mistakes#

Practice#

Practice exercise

How many rows does customers FULL OUTER JOIN orders return, and how many of them have a NULL in o.order_id? Explain using the three kinds of rows.

Show hint

Count matched pairs, unmatched customers, and unmatched orders separately.

Show solution
  • Matched pairs: 3 (Asha ×2, Ravi ×1)
  • Customers with no order: 2 (Meera, John), with o.order_id = NULL
  • Orders with no customer: 1 (order 104)

Total: 3 + 2 + 1 = 6 rows, of which 2 have a NULL order_id.

Key takeaway#

Finished this lesson?