Tutorials Logic, IN +91 8092939553 info@tutorialslogic.com
FAQs Support
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Interview Questions Website Development
Compiler Tutorials

MySQL Joins

What are Joins?

A JOIN combines rows from two or more tables based on a related column. The shop database has four related tables: customers, orders, order_items, and products. Joins let you query across all of them in a single statement.

INNER JOIN and LEFT JOIN
-- INNER JOIN: only rows with a match in BOTH tables
-- Returns customers who have placed at least one order
SELECT
    c.customer_id,
    CONCAT(c.first_name, ' ', c.last_name) AS customer_name,
    o.order_id,
    o.total,
    o.status
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
ORDER BY c.customer_id;

-- LEFT JOIN: all rows from the LEFT table, matched rows from the right
-- Returns ALL customers, including those with no orders (NULL for order columns)
SELECT
    c.customer_id,
    CONCAT(c.first_name, ' ', c.last_name) AS customer_name,
    COUNT(o.order_id)                       AS order_count,
    COALESCE(SUM(o.total), 0)               AS total_spent
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.first_name, c.last_name
ORDER BY total_spent DESC;
RIGHT JOIN and FULL OUTER JOIN (via UNION)
-- RIGHT JOIN: all rows from the RIGHT table, matched rows from the left
-- Returns all orders, including those with no matching customer (unusual but possible)
SELECT
    c.customer_id,
    CONCAT(c.first_name, ' ', c.last_name) AS customer_name,
    o.order_id,
    o.total
FROM customers c
RIGHT JOIN orders o ON c.customer_id = o.customer_id;

-- FULL OUTER JOIN: MySQL doesn't support FULL OUTER JOIN directly
-- Simulate it with LEFT JOIN UNION RIGHT JOIN
SELECT c.customer_id, c.first_name, o.order_id, o.total
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id

UNION

SELECT c.customer_id, c.first_name, o.order_id, o.total
FROM customers c
RIGHT JOIN orders o ON c.customer_id = o.customer_id
WHERE c.customer_id IS NULL;
CROSS JOIN and SELF JOIN
-- CROSS JOIN: every row from table A combined with every row from table B
-- (Cartesian product — use carefully, can produce huge result sets)
SELECT c.first_name, p.name AS product_name
FROM customers c
CROSS JOIN products p
LIMIT 20;

-- SELF JOIN: join a table to itself
-- Example: find customers who share the same last name
SELECT
    a.customer_id AS id1,
    a.first_name  AS name1,
    b.customer_id AS id2,
    b.first_name  AS name2,
    a.last_name
FROM customers a
INNER JOIN customers b
    ON a.last_name = b.last_name
    AND a.customer_id < b.customer_id
ORDER BY a.last_name;

Multiple Table Joins

You can chain multiple JOINs to query across all four tables in the shop database in a single statement.

Joining customers, orders, order_items, and products
-- Full order detail: customer + order + items + product names
SELECT
    c.customer_id,
    CONCAT(c.first_name, ' ', c.last_name) AS customer_name,
    o.order_id,
    o.status,
    o.ordered_at,
    p.name                                 AS product_name,
    oi.quantity,
    oi.unit_price,
    (oi.quantity * oi.unit_price)          AS line_total
FROM customers c
INNER JOIN orders      o  ON c.customer_id  = o.customer_id
INNER JOIN order_items oi ON o.order_id     = oi.order_id
INNER JOIN products    p  ON oi.product_id  = p.product_id
WHERE o.status IN ('shipped', 'delivered')
ORDER BY o.ordered_at DESC, o.order_id, oi.item_id;

-- Find customers who have never placed an order (LEFT JOIN + NULL check)
SELECT c.customer_id, c.first_name, c.last_name, c.email
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;
JOIN with WHERE vs ON
-- Filtering in ON vs WHERE behaves differently with LEFT JOIN

-- Filter in WHERE: excludes non-matching rows (effectively becomes INNER JOIN)
SELECT c.first_name, o.order_id, o.status
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE o.status = 'delivered';   -- customers with no orders are excluded

-- Filter in ON: keeps all left-table rows, filters only the joined rows
SELECT c.first_name, o.order_id, o.status
FROM customers c
LEFT JOIN orders o
    ON c.customer_id = o.customer_id
    AND o.status = 'delivered';  -- customers with no delivered orders still appear (NULL)

Key Takeaways
  • INNER JOIN returns only rows where there is a match in BOTH tables.
  • LEFT JOIN returns ALL rows from the left table + matching rows from the right (NULL for no match).
  • RIGHT JOIN returns ALL rows from the right table + matching rows from the left (NULL for no match).
  • FULL OUTER JOIN returns all rows from both tables (MySQL uses UNION of LEFT and RIGHT JOIN).
  • CROSS JOIN returns the Cartesian product — every row from table A combined with every row from table B.
  • Always use table aliases (a, b) in multi-table joins for cleaner, faster queries.
  • Index the JOIN columns (foreign keys) for dramatically better performance on large tables.
Common Mistakes to Avoid
WRONG SELECT * FROM orders, customers WHERE orders.cid = customers.id
RIGHT SELECT * FROM orders INNER JOIN customers ON orders.cid = customers.id
Implicit joins (comma syntax) are harder to read and maintain. Always use explicit JOIN syntax.
WRONG LEFT JOIN without checking for NULLs
RIGHT WHERE right_table.id IS NULL to find unmatched rows
LEFT JOIN + WHERE right.id IS NULL is the standard way to find rows in table A that have no match in table B.

Frequently Asked Questions

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.