What Is SQL INNER JOIN?
The SQL INNER JOIN keyword selects records that have matching values in both tables. If a row in the left table has no corresponding match in the right table, that row is excluded from the result. Similarly, unmatched rows in the right table are also excluded.
Think of it like finding common friends between two people — only the names that appear in both lists are returned. As you learned in Chapter 20: SQL Joins Introduction, JOINs let you combine data from multiple tables. INNER JOIN is the most restrictive and most frequently used type.
SQL INNER JOIN Syntax
Here is the basic SQL INNER JOIN syntax:
SELECT column_name(s)
FROM table1
INNER JOIN table2
ON table1.column_name = table2.column_name;
The ON clause specifies the condition used to match rows between the two tables. This is usually a primary key and foreign key relationship.
💡 Key Point About INNER JOIN
INNER JOIN and JOIN are the same in SQL. Writing JOIN without specifying a type defaults to INNER JOIN.
Sample Tables for Examples
We will use the Customers and Orders tables throughout this chapter. These are the same tables used across our SQL Tutorial course.
+----+----------------+-----------+---------+
| ID | CustomerName | City | Country |
+----+----------------+-----------+---------+
| 1 | Rahul Sharma | Mumbai | India |
| 2 | Sarah Johnson | New York | USA |
| 3 | Amit Patel | Delhi | India |
| 4 | Lisa Chen | Singapore | SG |
| 5 | David Brown | London | UK |
+----+----------------+-----------+---------+
+----+------------+------------+--------+---------+
| ID | CustomerID | OrderDate | Amount | Status |
+----+------------+------------+--------+---------+
| 1 | 1 | 2026-01-15 | 250.00 | Shipped |
| 2 | 2 | 2026-01-18 | 430.00 | Pending |
| 3 | 1 | 2026-02-01 | 180.00 | Shipped |
| 4 | 3 | 2026-02-10 | 520.00 | Shipped |
| 5 | 4 | 2026-03-05 | 310.00 | Pending |
+----+------------+------------+--------+---------+
Notice that Customer ID 5 (David Brown) has no orders, and every order belongs to an existing customer.
SQL INNER JOIN Example
Let us write an SQL INNER JOIN example that retrieves each customer’s name along with their order amount:
SELECT Customers.CustomerName, Orders.Amount, Orders.OrderDate
FROM Customers
INNER JOIN Orders
ON Customers.ID = Orders.CustomerID;
+----------------+--------+------------+ | CustomerName | Amount | OrderDate | +----------------+--------+------------+ | Rahul Sharma | 250.00 | 2026-01-15 | | Sarah Johnson | 430.00 | 2026-01-18 | | Rahul Sharma | 180.00 | 2026-02-01 | | Amit Patel | 520.00 | 2026-02-10 | | Lisa Chen | 310.00 | 2026-03-05 | +----------------+--------+------------+
Notice that David Brown (Customer ID 5) does not appear in the result because he has no matching row in the Orders table. This is exactly how INNER JOIN works — it only returns matched rows.
SQL INNER JOIN with Aliases
Writing full table names can get repetitive. As you learned in Chapter 19: SQL Aliases, you can use short aliases to simplify your queries:
SELECT c.CustomerName, o.Amount, o.Status
FROM Customers AS c
INNER JOIN Orders AS o
ON c.ID = o.CustomerID;
This produces the same result as the previous query but is much cleaner to read and write.
SQL INNER JOIN with WHERE Clause
You can combine INNER JOIN with a WHERE clause to filter joined results further:
SELECT c.CustomerName, o.Amount, o.Status
FROM Customers AS c
INNER JOIN Orders AS o
ON c.ID = o.CustomerID
WHERE o.Status = 'Shipped';
+----------------+--------+---------+ | CustomerName | Amount | Status | +----------------+--------+---------+ | Rahul Sharma | 250.00 | Shipped | | Rahul Sharma | 180.00 | Shipped | | Amit Patel | 520.00 | Shipped | +----------------+--------+---------+
The JOIN matches the rows first, and then the WHERE clause filters only the shipped orders.
SQL INNER JOIN Multiple Tables
In real-world databases, you often need to join more than two tables. You can chain multiple INNER JOINs in a single query. Let us add a Products table and an OrderDetails table to see this in action.
+----+---------+-----------+-----+
| ID | OrderID | ProductID | Qty |
+----+---------+-----------+-----+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 3 | 2 |
| 3 | 2 | 4 | 1 |
| 4 | 4 | 2 | 3 |
+----+---------+-----------+-----+
SELECT c.CustomerName, p.ProductName, od.Qty
FROM Customers AS c
INNER JOIN Orders AS o ON c.ID = o.CustomerID
INNER JOIN OrderDetails AS od ON o.ID = od.OrderID
INNER JOIN Products AS p ON od.ProductID = p.ID;
+----------------+----------------+-----+ | CustomerName | ProductName | Qty | +----------------+----------------+-----+ | Rahul Sharma | Laptop Pro | 1 | | Rahul Sharma | Wireless Mouse | 2 | | Sarah Johnson | Monitor 27" | 1 | | Amit Patel | Desk Lamp | 3 | +----------------+----------------+-----+
Each additional INNER JOIN adds another table to the chain. The key is to always match the correct foreign key with its primary key using the ON clause.
| Feature | INNER JOIN | LEFT JOIN |
|---|---|---|
| Returns | Only matched rows | All rows from left table + matches |
| Unmatched rows | Excluded | Filled with NULL |
| Use case | Find records that exist in both tables | Find all records from one table, even without matches |
| Performance | Generally faster | Slightly more work for the database |
You will learn about LEFT JOIN in detail in the next chapter.
⚠️ Common Mistake with INNER JOIN
Forgetting the ON clause or writing an incorrect join condition can produce a Cartesian product — every row from table A paired with every row from table B. Always double-check your ON conditions.
If you work with data regularly, explore our ready-made Dashboard Templates on NextGenTemplates that use SQL-powered data for business reporting.
📺 Visit our YouTube channel @NeoTechNavigators for step-by-step video tutorials and dashboard demos on this topic.
🧪 Try It Yourself
Write a query to display each customer’s name, order amount, and order date — but only for orders with an amount greater than 300. Use INNER JOIN with the Customers and Orders tables.
SELECT c.CustomerName, o.Amount, o.OrderDate
FROM Customers AS c
INNER JOIN Orders AS o
ON c.ID = o.CustomerID
WHERE o.Amount > 300;
Expected Output:
+----------------+--------+------------+ | CustomerName | Amount | OrderDate | +----------------+--------+------------+ | Sarah Johnson | 430.00 | 2026-01-18 | | Amit Patel | 520.00 | 2026-02-10 | | Lisa Chen | 310.00 | 2026-03-05 | +----------------+--------+------------+
Great work! You successfully combined INNER JOIN with a WHERE filter.
📝 What You Learned in This Chapter
INNER JOIN— returns only rows with matching values in both tables- The
ONclause defines the condition for matching rows JOINandINNER JOINare identical in SQL- You can chain multiple INNER JOINs to join three or more tables
- Combine INNER JOIN with
WHEREto further filter results - Unmatched rows from either table are excluded from the result
Frequently Asked Questions
JOIN without specifying a type is the same as writing INNER JOIN. Both return only matched rows from the joined tables.INNER JOIN clauses in a single query. Each additional JOIN requires its own ON condition specifying how the new table relates to the existing ones. For example, joining Customers, Orders, and Products in one query is very common.NULL values.ON clause are indexed for optimal speed. For more details, refer to the official MySQL JOIN documentation.📖 Chapter 21 of 30 — SQL Tutorial on Neotech Navigators


