Data AnalyticsSQL for Analyticsbeginner
Updated:

SQL Joins Explained for Data Analysts

4 min read

Businesses split data across tables. Learn INNER, LEFT, RIGHT and FULL joins to stitch orders to customers and products for reports that show names, not IDs.

TL;DR – Quick Answer

A SQL join combines rows from two tables using a matching column, like a customer_id shared by an orders table and a customers table. INNER JOIN keeps only rows that match in both tables; LEFT JOIN keeps every row from the left table and fills unmatched right-side columns with NULL; RIGHT and FULL joins do the mirror and union. Analysts use joins constantly to report human-readable names and attributes instead of raw IDs.

On This Page

Real businesses never keep everything in one table. Orders live in an orders table, customer details in a customers table, product attributes in a products table. That design keeps data clean, but it means almost every report you write as an analyst has to stitch tables back together — because a manager wants to see the customer's name and city, not a bare customer_id. Joins are how you do that, and they are among the most-used and most-tested skills in the analyst toolkit.

This tutorial explains the four join types through the lens of reporting on customers and orders. It follows the reporting basics in the SQL for analytics path and pairs naturally with grouping.

Two tables to join

-- customers
customer_id | customer_name | city
------------+---------------+----------
1           | Aarti         | Hyderabad
2           | Bhaskar       | Hyderabad
3           | Chitra        | Pune
4           | Devan         | Chennai

-- orders
order_id | customer_id | amount
---------+-------------+-------
1001     | 1           | 1200
1002     | 2           | 8500
1003     | 3           | 1200
1004     | 1           | 600
1005     | 9           | 4000

Notice two things: customer 4 (Devan) has no orders, and order 1005 references customer_id 9, who does not exist in the customers table. These mismatches are exactly where the join types differ.

INNER JOIN: only matched rows

INNER JOIN keeps only rows that have a match on both sides. To report each order with its customer's name:

SELECT o.order_id, c.customer_name, o.amount
FROM orders o
INNER JOIN customers c
    ON o.customer_id = c.customer_id;
order_id | customer_name | amount
---------+---------------+-------
1001     | Aarti         | 1200
1002     | Bhaskar       | 8500
1003     | Chitra        | 1200
1004     | Aarti         | 600

Order 1005 vanishes because customer_id 9 has no match, and Devan never appears because he placed no orders. INNER JOIN is the right choice when you only want fully matched data. The o and c are table aliases that keep the query short and let you qualify columns that exist in both tables.

LEFT JOIN: keep every left row

LEFT JOIN returns every row from the left (first) table, matched where possible and filled with NULL where not. To list every customer and their orders, including customers with none:

SELECT c.customer_name, o.order_id, o.amount
FROM customers c
LEFT JOIN orders o
    ON c.customer_id = o.customer_id;
customer_name | order_id | amount
--------------+----------+-------
Aarti         | 1001     | 1200
Aarti         | 1004     | 600
Bhaskar       | 1002     | 8500
Chitra        | 1003     | 1200
Devan         | NULL     | NULL

Devan now appears with NULLs, because LEFT JOIN refuses to drop him. This is the single most useful pattern in analytics: it lets you report on the complete set of entities, not just the ones with activity. "Every customer, including those who never ordered" or "every product, including those with zero sales" both require a LEFT JOIN.

A LEFT JOIN also finds the gaps. To list customers with no orders at all:

SELECT c.customer_name
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;

The WHERE ... IS NULL keeps only the unmatched rows — a standard "who is missing" report.

RIGHT and FULL joins

RIGHT JOIN is a mirror of LEFT JOIN: it keeps every row from the right table. Most analysts avoid it and simply reorder the tables to use LEFT JOIN, which reads more naturally. FULL OUTER JOIN keeps unmatched rows from both sides at once — every customer and every order, with NULLs wherever there is no match. It is useful for reconciliation reports where you want to surface orphans on either side, like our order 1005 pointing at a missing customer.

Joins and grouping together

Joins get their real power when combined with grouping. Total revenue per city needs the customer table for the city and the orders table for the amount:

SELECT c.city,
       COUNT(o.order_id) AS orders,
       SUM(o.amount)     AS revenue
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.city
ORDER BY revenue DESC;

The LEFT JOIN ensures a city with no orders still shows up with zero. This join-then-group shape is the backbone of nearly every dashboard, which is why it connects so tightly to GROUP BY and HAVING.

Common mistakes

  • Row fan-out inflating totals. If the join key is not unique on one side, rows multiply and SUM/COUNT overstate reality. Confirm the key is unique where you assume it is, and sanity-check totals.
  • Using INNER JOIN when you needed LEFT. An INNER JOIN silently drops entities with no matches, so "customers with zero orders" simply disappear and your report looks complete when it is not.
  • Filtering a LEFT JOIN's right table in WHERE. Putting WHERE o.amount > 1000 on a LEFT JOIN turns it back into an inner join by discarding the NULL rows. Put such conditions in the ON clause if you want to preserve unmatched left rows.
  • Ambiguous column names. When both tables share a column name, referencing it unqualified errors out. Always alias tables and prefix shared columns.

In interviews

Joins are the heart of analyst SQL interviews. Expect "customers who never placed an order" (LEFT JOIN plus IS NULL), "total revenue per city" (join plus GROUP BY), and the conceptual "difference between INNER and LEFT JOIN". A favourite trap is asking why a join returned too many rows — the answer is a non-unique key causing fan-out. Being able to explain fan-out and the LEFT-JOIN-then-filter pitfall marks you as someone who has debugged real reports.

Where this fits in your learning path

Joins connect the tables that grouping and aggregating then summarize, so they pair with GROUP BY and HAVING on nearly every dashboard. When a table needs to join to itself — employees to managers, or comparing rows within one table — continue to self joins. Joins are a graded skill throughout the data analyst roadmap.

Frequently Asked Questions

What is the difference between INNER JOIN and LEFT JOIN?
INNER JOIN returns only rows that have a match in both tables, so unmatched rows disappear. LEFT JOIN returns all rows from the left table and fills missing right-side values with NULL. Use INNER when you only want matched data, and LEFT when you must keep every left-side row, such as every customer even those with no orders.
How do I join two tables in SQL?
Name both tables and specify the matching condition: SELECT ... FROM orders o JOIN customers c ON o.customer_id = c.customer_id. The ON clause states which columns must match. Prefix columns with table aliases when the same name exists in both tables to avoid ambiguity.
Why does my join return more rows than expected?
Usually because the join key is not unique on one side, so each left row matches several right rows and the result fans out. This silently inflates counts and sums. Check that your join key is unique where you expect it to be, and verify totals against a known figure.
When should I use a RIGHT JOIN?
Rarely. A RIGHT JOIN keeps all rows from the right table and is just a LEFT JOIN with the tables swapped. Most analysts write LEFT JOINs for readability and reserve RIGHT JOIN for cases where reordering the tables would be awkward. FULL OUTER JOIN keeps unmatched rows from both sides.
What is the difference between a join and a UNION?
A join combines columns from two tables side by side based on a matching key, widening the result. A UNION stacks rows from two queries on top of each other, lengthening the result, and requires matching column counts and types. Joins answer 'bring related attributes together'; UNION answers 'combine two similar lists'.

Want to Build Your Career in Data Analytics with AI?

Join CodeBegun and train with working industry engineers — View the Data Analytics curriculum

Apply for Demo Class →
Siva Prasad Galaba
Founder, CodeBegun · Staff Engineer

Founder of CodeBegun. 15+ years building Java systems at companies like Crunchyroll. Teaches Java, Spring Boot and system design the way the industry actually works, and mentors students through projects, mock interviews and placement preparation.

Technically reviewed by CodeBegun Technical TeamLast reviewed 16 July 2026 LinkedIn
Chat with us