SQL Joins, Grouping and Aggregation Demystified: A Complete Practical Guide

Understanding SQL Joins β€” With Examples

Joins are used in SQL to combine rows from two or more tables based on a related column between them.

We’ll use two sample tables throughout:

πŸ“˜ Table: students

student_idname
1Alice
2Bob
3Charlie
4David

πŸ“˜ Table: courses

course_idstudent_idcourse_name
1011Math
1022Science
1031Physics
1045Chemistry

βœ… 1. INNER JOIN (Only Matching Records)

Returns only the rows where there is a match in both tables.

SELECT s.name, c.course_name
FROM students s
INNER JOIN courses c ON s.student_id = c.student_id;

🧾 Result:

namecourse_name
AliceMath
BobScience
AlicePhysics

student_id = 5 in courses doesn’t match any student, so it’s excluded.

βœ… 2. LEFT JOIN (All from Left + Matching from Right)

Returns all rows from the left table, and matched rows from the right. Non-matches return NULL.

SELECT s.name, c.course_name
FROM students s
LEFT JOIN courses c ON s.student_id = c.student_id;

🧾 Result:

namecourse_name
AliceMath
AlicePhysics
BobScience
CharlieNULL
DavidNULL

Students with no course still appear.


βœ… 3. RIGHT JOIN (All from Right + Matching from Left)

Returns all rows from the right table, and matched rows from the left. Non-matches return NULL.

SELECT s.name, c.course_name
FROM students s
RIGHT JOIN courses c ON s.student_id = c.student_id;

🧾 Result:

namecourse_name
AliceMath
BobScience
AlicePhysics
NULLChemistry

The course with student_id = 5 has no matching student.


βœ… 4. FULL OUTER JOIN (All from Both Tables)

Returns all records when there is a match in either left or right table. Non-matching rows return NULL.

SELECT s.name, c.course_name
FROM students s
FULL OUTER JOIN courses c ON s.student_id = c.student_id;

🧾 Result:

namecourse_name
AliceMath
BobScience
AlicePhysics
CharlieNULL
DavidNULL
NULLChemistry

All rows from both tables, including non-matches.


βœ… 5. CROSS JOIN (Cartesian Product)

Returns all combinations of rows β€” each row from the first table is paired with all rows from the second.

SELECT s.name, c.course_name
FROM students s
CROSS JOIN courses c;

🧾 If students has 4 rows and courses has 4 rows β†’ Output: 16 rows

⚠️ Use with caution β€” grows quickly with data size!


βœ… 6. SELF JOIN (Join a table to itself)

Used when rows in a table are related to other rows in the same table.

Example: Employee hierarchy

CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    name VARCHAR(50),
    manager_id INT
);
SELECT e.name AS employee, m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.emp_id;

🧾 Result:

employeemanager
JohnAlice
AliceNULL
BobAlice

🧠 Quick Summary Table

Join TypeIncludes Non-Matching Rows FromUse Case
INNER JOIN❌ NoneOnly exact matches
LEFT JOINβœ… Left table onlyWhen you want all left records
RIGHT JOINβœ… Right table onlyWhen you want all right records
FULL OUTER JOINβœ… Both tablesKeep everything
CROSS JOIN❌ None (All combinations)Combinatorics, testing, pivoting
SELF JOINπŸ” Same tableTree/hierarchy-based tables

What is a NATURAL JOIN in SQL?

A NATURAL JOIN is a type of join that automatically joins two tables based on all columns with the same name in both tables β€” without explicitly specifying the join condition.

βœ… Syntax:

SELECT * 
FROM table1
NATURAL JOIN table2;

⚠️ Important Points:

  • It finds columns with the same name in both tables and joins based on those.

  • You don’t need to specify ON or USING.

  • It’s often equivalent to:

SELECT * 
FROM table1
JOIN table2 USING (common_column_name);

SQL Aggregation and GROUP BY

πŸ“Œ What is GROUP BY?

The GROUP BY clause is used to group rows that have the same values in specified columns and perform aggregate functions like SUM, COUNT, AVG, MAX, and MIN on each group.

πŸ”’ Common Aggregate Functions in SQL

FunctionDescription
COUNT()Counts the number of rows
SUM()Adds up values in a column
AVG()Calculates the average
MIN()Gets the minimum value
MAX()Gets the maximum value

πŸ§ͺ Sample Table: orders

order_idcustomer_idamountproduct
1101500Mobile
21021000Laptop
3101150Charger
41032000TV
5102700Headphones

βœ… 1. Using GROUP BY with SUM()

-- Total amount spent by each customer
SELECT customer_id, SUM(amount) AS total_spent
FROM orders
GROUP BY customer_id;

🧾 Output:

customer_idtotal_spent
101650
1021700
1032000

βœ… 2. Using GROUP BY with COUNT()

-- Number of orders per customer
SELECT customer_id, COUNT(*) AS order_count
FROM orders
GROUP BY customer_id;

🧾 Output:

customer_idorder_count
1012
1022
1031

βœ… 3. Using GROUP BY with AVG()

-- Average order amount per customer
SELECT customer_id, AVG(amount) AS avg_order
FROM orders
GROUP BY customer_id;

🧾 Output:

customer_idavg_order
101325
102850
1032000

βœ… 4. Using GROUP BY with MIN() and MAX()

-- Min and max order amount per customer
SELECT customer_id, MIN(amount) AS min_order, MAX(amount) AS max_order
FROM orders
GROUP BY customer_id;

🧾 Output:

customer_idmin_ordermax_order
101150500
1027001000
10320002000

βœ… 5. Grouping by Multiple Columns

-- Total amount per customer per product
SELECT customer_id, product, SUM(amount) AS total
FROM orders
GROUP BY customer_id, product;

🧾 Output:

customer_idproducttotal
101Mobile500
101Charger150
102Laptop1000
102Headphones700
103TV2000

βœ… 6. Using HAVING with GROUP BY

HAVING is like WHERE, but used after grouping to filter group-level results.

-- Customers who spent more than 1000 total
SELECT customer_id, SUM(amount) AS total_spent
FROM orders
GROUP BY customer_id
HAVING SUM(amount) > 1000;

🧾 Output:

customer_idtotal_spent
1021700
1032000

πŸ”„ Difference Between WHERE and HAVING

ClauseApplies ToExample Use
WHERERows (before grouping)WHERE amount > 500
HAVINGGroups (after grouping)HAVING SUM(amount) > 1000

🧠 Tips for Using Aggregations

  • Every column in SELECT (that is not aggregated) must be in GROUP BY.

  • You can use ORDER BY after GROUP BY to sort results.

  • You can nest aggregate functions (e.g., ROUND(AVG(...))).

0
Subscribe to my newsletter

Read articles from Yash Sakhareliya directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Yash Sakhareliya
Yash Sakhareliya