SQL INNER JOIN vs LEFT JOIN Explained
Joins combine rows from two tables that match on a condition. An INNER JOIN keeps only rows with a match on both sides; a LEFT JOIN keeps every row from the left table and fills in NULL when there is no match. Most join bugs come down to choosing the wrong one.
Examples run in MySQL 8 and PostgreSQL · Updated
In short
INNER JOIN: only rows that match on both sides.LEFT JOIN: all left rows, NULLs where the right side has no match.- Count matches with
COUNT(right.id), notCOUNT(*). - A
WHEREon the right table can undo aLEFT JOIN.
Which rows survive
Our data has one employee without a department (Zoya) and one department without employees (Finance). An inner join drops both. A left join from employees keeps Zoya with a NULL department name; a left join from departments keeps Finance with no employees.
Which table is "left" matters: it is the one written first, after FROM. Put the table whose rows you must keep on the left.
Counting with a LEFT JOIN
When a left row has no match, the joined row still exists, with NULLs on the right. COUNT(*) counts that row as 1; COUNT(e.emp_id) skips NULLs and correctly gives 0.
The example tables
Every example on this page uses these tables. They are small on purpose, so you can check each result by eye.
employees
| emp_id | name | dept_id | salary | manager_id | hire_date |
|---|---|---|---|---|---|
| 1 | Aarav | 10 | 95000 | NULL | 2021-03-01 |
| 2 | Diya | 10 | 88000 | 1 | 2022-06-15 |
| 3 | Kabir | 10 | 72000 | 1 | 2023-01-10 |
| 4 | Meera | 20 | 64000 | NULL | 2020-11-20 |
| 5 | Rohan | 20 | 58000 | 4 | 2024-02-05 |
| 6 | Isha | 30 | 61000 | NULL | 2022-09-12 |
| 7 | Arjun | 20 | 64000 | 4 | 2023-07-30 |
| 8 | Zoya | NULL | 52000 | NULL | 2024-05-01 |
departments
| dept_id | dept_name |
|---|---|
| 10 | Engineering |
| 20 | Sales |
| 30 | Marketing |
| 40 | Finance |
Examples
INNER JOIN
Only employees with a matching department. Zoya disappears, and Finance never appears.
SELECT e.name, d.dept_name
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
ORDER BY e.emp_id;| name | dept_name |
|---|---|
| Aarav | Engineering |
| Diya | Engineering |
| Kabir | Engineering |
| Meera | Sales |
| Rohan | Sales |
| Isha | Marketing |
| Arjun | Sales |
LEFT JOIN keeps unmatched rows
Every employee is kept; Zoya gets NULL for dept_name.
SELECT e.name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id
ORDER BY e.emp_id;| name | dept_name |
|---|---|
| Aarav | Engineering |
| Diya | Engineering |
| Kabir | Engineering |
| Meera | Sales |
| Rohan | Sales |
| Isha | Marketing |
| Arjun | Sales |
| Zoya | NULL |
Headcount including empty departments
Start from departments so Finance is kept, and count employee ids so it shows 0, not 1.
SELECT d.dept_name, COUNT(e.emp_id) AS employees
FROM departments d
LEFT JOIN employees e ON e.dept_id = d.dept_id
GROUP BY d.dept_name
ORDER BY employees DESC, d.dept_name;| dept_name | employees |
|---|---|
| Engineering | 3 |
| Sales | 3 |
| Marketing | 1 |
| Finance | 0 |
Common mistakes
- Filtering the right table in WHERE.
LEFT JOIN … WHERE d.dept_name = 'Sales'removes the NULL rows, turning it into an inner join. Put such conditions in theONclause instead. - COUNT(*) after a LEFT JOIN. It counts unmatched rows as 1. Count a column from the right table.
- Join fan-out. Joining to a table with several matches per row multiplies rows, so sums and counts grow. Aggregate first in a subquery or CTE, then join.
Practise INNER JOIN vs LEFT JOIN
Interview questions that use this concept, easiest first. Each one has the step-by-step visualizer and answer checking.
Users With Zero Searches
Find registered account profiles that have never submitted a search query using an outer join.
Ad Click-Through Rate (CTR)
Calculate the percentage CTR per ad campaign rounded to 2 decimals, safely handling campaigns with zero impressions.
Google Maps: High-Impact Local Guides
Find verified reviewers who submitted at least 2 photo reviews in San Francisco or Mountain View.
Google Drive: External Sensitive File Shares
Audit sensitive files shared with non-Google email addresses to identify potential data exposure risks.
Employees Earning More Than Their Managers
Join the employee table with itself to find staff members whose salary exceeds their direct manager.
Customers Who Never Order
Identify all customer records that have no matching entries in the Orders table.
Want a full set? Work through the SQL Joins study plan.
Questions people ask
- Is LEFT JOIN the same as LEFT OUTER JOIN?
- Yes. OUTER is optional; both mean the same thing in MySQL and PostgreSQL.
- Does MySQL support FULL OUTER JOIN?
- No. PostgreSQL does; in MySQL you combine a LEFT JOIN and a RIGHT JOIN with UNION.