OUTER JOIN
LEFT JOIN keeps every row of the first table, matched or not; RIGHT JOIN keeps every row of the second; FULL OUTER JOIN keeps both. Rows with no match get NULL, which also lets you find what's missing.
Journeyman · T-SQL · SQL · Updated
After this lesson you can
- Keep rows without a match with LEFT, RIGHT and FULL OUTER JOIN
- Find rows that have no match with a LEFT JOIN and IS NULL
Key takeaways
LEFT JOINkeeps every row of the table named first,RIGHT JOINevery row of the joined table, andFULL OUTER JOINevery row of both.- A row with no match gets
NULLin every column of the other table. - To find rows with no match, use a
LEFT JOIN, then keep only the rows where the right table's keyIS NULL. - When counting with an outer join, use
COUNT(o.OrderId), notCOUNT(*), so a customer with no orders counts as 0. - Put the table you want to keep first and write
LEFT JOIN; everyRIGHT JOINcan be turned round into one.
An inner join drops the rows that have no match. An outer join keeps them, and fills the other table's columns with NULL.
LEFT and RIGHT
In a join, the table named first (after FROM) is the left table, and the joined one is the right table.
LEFT JOIN (also written LEFT OUTER JOIN) keeps every row of the left table, matched or not:
SELECT COUNT(*) AS Rows
FROM Customers AS c
LEFT JOIN Orders AS o
ON c.CustomerId = o.CustomerId;
| Rows |
|---|
| 832 |
That's the 830 orders, plus one row for each of the two customers with no orders, with NULL in every Orders column.
RIGHT JOIN keeps every row of the right table instead. These two give the same rows:
SELECT COUNT(*) AS Rows
FROM Orders AS o
RIGHT JOIN Customers AS c
ON o.CustomerId = c.CustomerId;
Most people write LEFT JOIN and put the table they want to keep first. It reads more naturally, and every RIGHT JOIN can be turned round into one.
Finding what's missing
The NULLs are useful. Which customers have never ordered? Keep every customer with a LEFT JOIN, then keep only the rows where no order matched:
SELECT c.CompanyName, o.OrderId
FROM Customers AS c
LEFT JOIN Orders AS o
ON c.CustomerId = o.CustomerId
WHERE o.OrderId IS NULL;
| CompanyName | OrderId |
|---|---|
| FISSA Fabrica Inter. Salchichas S.A. | NULL |
| Paris spécialités | NULL |
This LEFT JOIN, then IS NULL pattern answers every "which ones have none?" question: products never ordered, employees with no orders, categories with no products.
Counting with an outer join
To count orders per customer, including customers with none, use COUNT on a column of the right table. COUNT(*) would count the NULL row as 1; COUNT(o.OrderId) skips it:
SELECT TOP (4) c.CompanyName, COUNT(o.OrderId) AS Orders
FROM Customers AS c
LEFT JOIN Orders AS o
ON c.CustomerId = o.CustomerId
GROUP BY c.CompanyName
ORDER BY Orders, c.CompanyName;
| CompanyName | Orders |
|---|---|
| FISSA Fabrica Inter. Salchichas S.A. | 0 |
| Paris spécialités | 0 |
| Centro comercial Moctezuma | 1 |
| GROSELLA-Restaurante | 2 |
FULL OUTER JOIN
FULL OUTER JOIN keeps unmatched rows from both tables. Which customers and suppliers share a city?
SELECT COALESCE(c.City, s.City) AS City, c.CompanyName AS Customer, s.CompanyName AS Supplier
FROM Customers AS c
FULL OUTER JOIN Suppliers AS s
ON c.City = s.City
WHERE COALESCE(c.City, s.City) IN ('Berlin', 'Madrid', 'Tokyo')
ORDER BY City, Customer;
| City | Customer | Supplier |
|---|---|---|
| Berlin | Alfreds Futterkiste | Heli Süßwaren GmbH & Co. KG |
| Madrid | Bólido Comidas preparadas | NULL |
| Madrid | FISSA Fabrica Inter. Salchichas S.A. | NULL |
| Madrid | Romero y tomillo | NULL |
| Tokyo | NULL | Tokyo Traders |
Berlin has both; Madrid has customers but no supplier; Tokyo has a supplier but no customer. COALESCE(c.City, s.City) takes whichever city isn't NULL.
| Join | Keeps every row of |
|---|---|
INNER JOIN |
Neither: only matches |
LEFT JOIN |
The left table |
RIGHT JOIN |
The right table |
FULL OUTER JOIN |
Both tables |
Check yourself
2 questions to try on the lesson page.
So what
Outer joins keep the rows an inner join would quietly drop, and the NULLs they leave behind point straight at what's missing: the customer who never ordered, the product nobody bought.