SQL INNER JOIN
SQL

SQL INNER JOIN: Match Rows from Two Tables (Examples)

SQL Tutorial · Chapter 20 of 32

The SQL INNER JOIN returns only the rows that have a matching value in both tables. If a customer has no orders, or an order points to a customer that does not exist, that row is left out. INNER JOIN is the default and most common join: writing just JOIN means INNER JOIN in every major database.

SQL INNER JOIN Syntax

SELECT columns
FROM table1
INNER JOIN table2
    ON table1.common_column = table2.common_column;

The ON condition usually compares a primary key in one table with a foreign key in the other. Use table aliases (c, o) to keep the query short.

Sample Tables

Customers
CustomerID Name City Country
1 Anita Sharma Mumbai India
2 John Smith London UK
3 Maria Garcia Madrid Spain
4 Wei Chen Singapore Singapore
5 Emma Brown Sydney Australia
Orders
OrderID CustomerID Product Amount OrderDate
101 1 Laptop 1200 2026-01-05
102 2 Mouse 25 2026-01-07
103 1 Monitor 300 2026-01-12
104 3 Keyboard 45 2026-02-02
105 6 Headset 80 2026-02-15
106 4 Laptop 1150 2026-03-01

Example 1: Basic INNER JOIN

SELECT c.Name, o.OrderID, o.Product, o.Amount
FROM Customers c
INNER JOIN Orders o ON o.CustomerID = c.CustomerID
ORDER BY o.OrderID;
Name OrderID Product Amount
Anita Sharma 101 Laptop 1200
John Smith 102 Mouse 25
Anita Sharma 103 Monitor 300
Maria Garcia 104 Keyboard 45
Wei Chen 106 Laptop 1150

Five rows. Emma Brown (no orders) and order 105 (customer 6 does not exist) are excluded. Anita Sharma appears twice because she has two matching orders.

Example 2: INNER JOIN with WHERE

SELECT c.Name, c.Country, o.Product
FROM Customers c
JOIN Orders o ON o.CustomerID = c.CustomerID
WHERE o.Amount > 100;
Name Country Product
Anita Sharma India Laptop
Anita Sharma India Monitor
Wei Chen Singapore Laptop

Example 3: INNER JOIN with GROUP BY

Joining then grouping gives you totals per customer with their names, something neither table can produce alone.

SELECT c.Name, COUNT(o.OrderID) AS Orders, SUM(o.Amount) AS Total
FROM Customers c
INNER JOIN Orders o ON o.CustomerID = c.CustomerID
GROUP BY c.Name
ORDER BY Total DESC;
Name Orders Total
Anita Sharma 2 1500
Wei Chen 1 1150
Maria Garcia 1 45
John Smith 1 25

Example 4: Extra Conditions in ON

ON may contain more than one condition. Here only January orders are joined.

SELECT c.Name, o.OrderID, o.OrderDate
FROM Customers c
INNER JOIN Orders o
    ON o.CustomerID = c.CustomerID
   AND o.OrderDate < '2026-02-01';
Name OrderID OrderDate
Anita Sharma 101 2026-01-05
John Smith 102 2026-01-07
Anita Sharma 103 2026-01-12

For an INNER JOIN this is equivalent to putting the date test in WHERE; for outer joins the two placements behave differently.

Example 5: Self Join

A table can be joined to itself to compare rows. This finds pairs of customers in the same country; with our data none share a country, so the result is empty, but the pattern is common for employee and manager tables.

SELECT a.Name AS Customer1, b.Name AS Customer2, a.Country
FROM Customers a
INNER JOIN Customers b
    ON a.Country = b.Country AND a.CustomerID < b.CustomerID;

Works in MySQL, SQL Server, PostgreSQL, SQLite

  • INNER JOIN syntax is identical in all four. JOIN, INNER JOIN and the comma-style FROM a, b WHERE a.id = b.id give the same result, but explicit INNER JOIN is clearest.
  • MySQL, PostgreSQL and SQLite support USING (CustomerID) as shorthand when the key column has the same name in both tables; SQL Server does not.
  • MySQL and SQLite also support NATURAL JOIN; avoid it, because it silently joins on every shared column name.

Common Mistakes

  • Omitting ON, which gives every combination of rows (a cross join).
  • Selecting CustomerID without a prefix when both tables contain it: “ambiguous column name”.
  • Expecting unmatched rows to appear; that needs LEFT, RIGHT or FULL JOIN.
  • Duplicated rows after joining to a table that has several matches per key; aggregate or use DISTINCT deliberately.

Practice Exercise

  1. List each order’s OrderID with the customer’s City.
  2. Show the total Amount ordered by customers from India.
Show answers
-- 1
SELECT o.OrderID, c.City
FROM Orders o INNER JOIN Customers c ON c.CustomerID = o.CustomerID;
-- 101 Mumbai, 102 London, 103 Mumbai, 104 Madrid, 106 Singapore

-- 2
SELECT SUM(o.Amount) AS IndiaTotal
FROM Orders o INNER JOIN Customers c ON c.CustomerID = o.CustomerID
WHERE c.Country = 'India';
-- 1500

Related Chapters

FAQ

What is the difference between JOIN and INNER JOIN?

None. JOIN on its own is shorthand for INNER JOIN in MySQL, SQL Server, PostgreSQL, SQLite and Oracle.

Does INNER JOIN return duplicate rows?

It returns one row for every matching pair. If a customer has three orders, that customer appears three times. That is correct behaviour, not duplication.

What happens to rows without a match in an INNER JOIN?

They are excluded from the result. To keep them, use LEFT JOIN, RIGHT JOIN or FULL JOIN.

Chapter 20 of 32 · SQL from Scratch: all 32 chapters

PK
Meet PK, the founder of NeotechNavigators.com! With over 15 years of experience in Data Visualization, Excel Automation, and dashboard creation. PK is a Microsoft Certified Professional who has a passion for all things in Excel. PK loves to explore new and innovative ways to use Excel and is always eager to share his knowledge with others. With an eye for detail and a commitment to excellence, PK has become a go-to expert in the world of Excel. Whether you're looking to create stunning visualizations or streamline your workflow with automation, PK has the skills and expertise to help you succeed. Join the many satisfied clients who have benefited from PK's services and see how he can take your data analysis skills to the next level!
https://neotechnavigators.com