Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

SQL Joins
DBMS

SQL Joins

Master every type of SQL join — INNER, LEFT, RIGHT, FULL OUTER, CROSS, SELF, and NATURAL — with syntax, examples, and real-world use cases.

SQL Joins

Relational databases store data in multiple tables. To answer questions that involve data from two or more tables, you need joins.

A join combines rows from two or more tables based on a related column (usually a foreign key).

Joins are the most important SQL concept for both daily work and interviews.


Learning Objectives

After completing this chapter, you will be able to:

  • Understand the purpose of joins.
  • Write INNER, LEFT, RIGHT, FULL OUTER, and CROSS joins.
  • Understand the difference between joins.
  • Write self-joins for recursive relationships.
  • Use NATURAL joins and understand their risks.
  • Choose the correct join for any query.
  • Answer join-related interview questions.

Sample Data

All examples use these two tables.

CREATE TABLE Customers (
    Customer_ID INT PRIMARY KEY,
    Name VARCHAR(50),
    City VARCHAR(50)
);

CREATE TABLE Orders (
    Order_ID INT PRIMARY KEY,
    Customer_ID INT,
    Amount DECIMAL(10,2),
    Order_Date DATE
);

Customers

Customer_IDNameCity
1RahulMumbai
2PriyaDelhi
3AmitMumbai
4SnehaBangalore
5VikramPune

Orders

Order_IDCustomer_IDAmountOrder_Date
1011500002024-01-15
1022150002024-01-16
1031250002024-02-01
1043300002024-02-05
1056100002024-03-01

Note:

  • Customer_ID 5 (Vikram) has no orders.
  • Order 105 has Customer_ID 6, which does not exist in Customers.

INNER JOIN

INNER JOIN returns only matching rows from both tables.

If a row in one table has no match in the other, it is excluded.

Syntax

SELECT columns
FROM TableA
INNER JOIN TableB ON TableA.key = TableB.key;

Example

SELECT c.Name, o.Order_ID, o.Amount
FROM Customers c
INNER JOIN Orders o ON c.Customer_ID = o.Customer_ID;
NameOrder_IDAmount
Rahul10150000
Priya10215000
Rahul10325000
Amit10430000

Result: 4 rows.

  • Vikram (no orders) is excluded.
  • Order 105 (non-existent customer) is excluded.

LEFT JOIN (LEFT OUTER JOIN)

LEFT JOIN returns all rows from the left table, plus matching rows from the right table.

If there is no match in the right table, the result shows NULL for the right-table columns.

Syntax

SELECT columns
FROM TableA
LEFT JOIN TableB ON TableA.key = TableB.key;

Example

SELECT c.Name, c.City, o.Order_ID, o.Amount
FROM Customers c
LEFT JOIN Orders o ON c.Customer_ID = o.Customer_ID;
NameCityOrder_IDAmount
RahulMumbai10150000
RahulMumbai10325000
PriyaDelhi10215000
AmitMumbai10430000
SnehaBangaloreNULLNULL
VikramPuneNULLNULL

Result: 6 rows — all customers, with NULLs where orders don’t exist.


RIGHT JOIN (RIGHT OUTER JOIN)

RIGHT JOIN returns all rows from the right table, plus matching rows from the left table.

Important: RIGHT JOIN is rarely used because the same result can be achieved by swapping the tables in a LEFT JOIN.

Syntax

SELECT columns
FROM TableA
RIGHT JOIN TableB ON TableA.key = TableB.key;

Example

SELECT c.Name, o.Order_ID, o.Amount
FROM Customers c
RIGHT JOIN Orders o ON c.Customer_ID = o.Customer_ID;
NameOrder_IDAmount
Rahul10150000
Priya10215000
Rahul10325000
Amit10430000
NULL10510000

Result: 5 rows — all orders, with NULLs where customer doesn’t exist.


FULL OUTER JOIN

FULL OUTER JOIN returns all rows from both tables.

Where matches exist, rows are combined. Where no match exists, NULLs fill the opposite side.

Syntax

SELECT columns
FROM TableA
FULL OUTER JOIN TableB ON TableA.key = TableB.key;

Example

SELECT c.Name, o.Order_ID, o.Amount
FROM Customers c
FULL OUTER JOIN Orders o ON c.Customer_ID = o.Customer_ID;
NameOrder_IDAmount
Rahul10150000
Rahul10325000
Priya10215000
Amit10430000
SnehaNULLNULL
VikramNULLNULL
NULL10510000

Result: 7 rows — all customers and all orders, with NULLs where no match exists.


Visual Summary

INNER:            LEFT:             RIGHT:            FULL:
┌─────┬─────┐    ┌─────┬─────┐    ┌─────┬─────┐    ┌─────┬─────┐
│     │     │    │  A  │     │    │     │  B  │    │  A  │  B  │
│     │     │    │     │     │    │     │     │    │     │     │
│     │     │    │     │     │    │     │     │    │     │     │
│  A∩B│     │    │  A∩B│     │    │  A∩B│     │    │  A∩B│     │
│     │     │    │     │     │    │     │     │    │     │     │
└─────┴─────┘    └─────┴─────┘    └─────┴─────┘    └─────┴─────┘
 Only matches   All from left    All from right    All from both

CROSS JOIN

CROSS JOIN returns the Cartesian product — every row from Table A combined with every row from Table B.

Syntax

SELECT columns
FROM TableA
CROSS JOIN TableB;

Example

SELECT c.Name, o.Order_ID
FROM Customers c
CROSS JOIN Orders o;

For 5 customers and 5 orders, the result has 5 × 5 = 25 rows.

NameOrder_ID
Rahul101
Rahul102
Rahul103
Rahul104
Rahul105
Priya101

When to Use

  • Generating all combinations (e.g., all products × all stores).
  • Creating test data.
  • Generating date ranges.

SELF JOIN

A SELF JOIN joins a table to itself.

Useful for hierarchical relationships (employee-manager, product categories).

Syntax

SELECT columns
FROM TableA t1
JOIN TableA t2 ON t1.column = t2.column;

Example

Emp_IDNameManager_ID
1RajNULL
2Rahul1
3Priya1
4Amit2
SELECT e.Name AS Employee, m.Name AS Manager
FROM Employees e
LEFT JOIN Employees m ON e.Manager_ID = m.Emp_ID;
EmployeeManager
RajNULL
RahulRaj
PriyaRaj
AmitRahul

SELF JOIN requires table aliases (otherwise you cannot reference the same table twice).


NATURAL JOIN

NATURAL JOIN automatically joins tables on columns with the same name.

SELECT * FROM Customers NATURAL JOIN Orders;

If both tables have a column named Customer_ID, the join is applied automatically.

Danger

  • You have no control over which columns are used for joining.
  • If someone adds a new column with a matching name later, the join behavior changes silently.
  • Never use NATURAL JOIN in production. Always use explicit JOIN with ON clause.

Join Performance Considerations

Join TypePerformance Note
INNERFastest when indexed correctly (primary key + foreign key indexes)
LEFTSimilar to INNER for matched rows; slower if most rows don’t match
FULLSlowest — needs to scan both tables completely
CROSSVery slow for large tables (produces M × N rows)
SELFSame as INNER (but same table scanned twice)

Indexing for Joins

Always index foreign key columns:

CREATE INDEX idx_customer_id ON Orders(Customer_ID);

Without this index, every join will scan the entire Orders table.


Practical Join Patterns

Pattern 1: Customers with no orders

SELECT c.*
FROM Customers c
LEFT JOIN Orders o ON c.Customer_ID = o.Customer_ID
WHERE o.Order_ID IS NULL;

Pattern 2: Top customers by spend

SELECT c.Name, SUM(o.Amount) AS Total_Spent
FROM Customers c
JOIN Orders o ON c.Customer_ID = o.Customer_ID
GROUP BY c.Name
ORDER BY Total_Spent DESC;

Pattern 3: Active vs inactive customers

SELECT
    c.Name,
    CASE WHEN o.Order_ID IS NOT NULL THEN 'Active' ELSE 'Inactive' END AS Status
FROM Customers c
LEFT JOIN Orders o ON c.Customer_ID = o.Customer_ID;

Interview Deep Dive

Q: What is the difference between INNER JOIN and LEFT JOIN?

A: INNER JOIN returns only rows that have matches in both tables. LEFT JOIN returns all rows from the left table and matching rows from the right table — non-matching left rows appear with NULLs for the right table’s columns. Use INNER JOIN when you only need complete data. Use LEFT JOIN when you need all records from the primary table regardless of matches.

Q: Can you give a real example of a self join?

A: Employee-Manager hierarchy. Each employee has a manager_id pointing to another employee. To get a list of employees with their manager names, you join the Employees table with itself. Also used for finding duplicate records, comparing rows within the same table, and traversing hierarchies.

Q: Why would anyone use CROSS JOIN intentionally?

A: For generating all combinations. Example: A retail company wants to see all possible product-and-store combinations for inventory planning. CROSS JOIN with 100 products and 50 stores produces 5000 combinations for analysis. Also used for generating date ranges and test data.

Q: When would you prefer a subquery over a JOIN?

A: Use a subquery when you only need data from one table and the condition depends on aggregated data from another table. Example: “Find customers who have placed more than 3 orders.” A subquery with COUNT is clearer. However, JOIN is generally faster because the optimizer can better plan the execution.


Key Takeaways

  • INNER JOIN returns only matching rows.
  • LEFT JOIN returns all rows from the left table.
  • RIGHT JOIN returns all rows from the right table (avoid — use LEFT JOIN instead).
  • FULL OUTER JOIN returns all rows from both tables.
  • CROSS JOIN returns the Cartesian product.
  • SELF JOIN joins a table to itself (needs aliases).
  • NATURAL JOIN is dangerous — always use explicit ON condition.
  • Index foreign key columns for join performance.
  • Use LEFT JOIN + WHERE IS NULL to find non-matching rows.

My Private Notes

Notes are auto-saved locally to this device.