📘 CodingMarble Learn

SQL Aggregates, GROUP BY, HAVING, ORDER BY and Equi-Join

Aggregate (multi-row) functions take many rows and return one value: MAX, MIN, SUM, AVG and COUNT. They skip NULL values, except COUNT(*), which counts every row. GROUP BY splits rows into groups with the same value so an aggregate runs once per group. HAVING filters those groups, while WHERE filters single rows before grouping. ORDER BY sorts the output in ascending or descending order. An equi-join combines two tables by matching rows where a common column is equal.

🎬 Step-by-step story

  1. Aggregate functions squeeze many rows into one answer.
  2. COUNT(column) skips NULL; COUNT(*) counts every row.
  3. GROUP BY makes one pile per value, and the aggregate runs on each pile.
  4. HAVING filters groups; ORDER BY sorts the result.
  5. An equi-join links rows of two tables where a common column is equal.
  6. Your turn: pick a query, predict the answer, watch the bars.

Tip: drag the 3D scene to turn it. Use two fingers to zoom.

🤔 Common doubts, cleared

Why does SUM give one row when the table has six?

SUM is an aggregate: it takes all rows together and gives one total.

Why is AVG 43000 and not 215000 ÷ 6?

Kabir's salary is NULL, and AVG skips NULL. So it divides by 5 filled values: 215000 ÷ 5 = 43000.

What does GROUP BY actually do to the rows?

It sorts the rows into piles with the same value (IT, HR, Sales). The aggregate then runs on each pile and gives one row per pile.

When do I use HAVING instead of WHERE?

When the condition uses an aggregate or is about a group (like COUNT(*) > 1). WHERE works on single rows before grouping.

Can I ORDER BY a column that is not in SELECT?

Yes, in MySQL you can sort by any column of the table, or by an aggregate like SUM(Salary).

What happens if I forget the WHERE in a join?

Every row of the first table pairs with every row of the second (Cartesian product), giving many wrong rows.

Why write E.Dept and not just Dept in a join?

Both tables have a Dept column, so SQL needs to know which one you mean.

Aggregate functions: MAX, MIN, AVG, SUM, COUNT

An aggregate (multi-row) function works on a whole column and returns one value. Table emp:

NameDeptSalary
AshaIT50000
RaviHR30000
MohanIT40000
ZoyaSales35000
KabirHRNULL
NehaIT60000
SELECT MAX(Salary) FROM emp;   -- 60000
SELECT MIN(Salary) FROM emp;   -- 30000
SELECT SUM(Salary) FROM emp;   -- 215000
SELECT AVG(Salary) FROM emp;   -- 43000  (215000 ÷ 5, NULL skipped)

MAX and MIN also work on text and dates (alphabetical / earliest-latest).

COUNT(column) vs COUNT(*)

SELECT COUNT(Salary) FROM emp;        -- 5  (NULL not counted)
SELECT COUNT(*) FROM emp;             -- 6  (every row)
SELECT COUNT(DISTINCT Dept) FROM emp; -- 3  (IT, HR, Sales)

All aggregates ignore NULL. Only COUNT(*) counts rows, so it includes the NULL row.

GROUP BY

GROUP BY puts rows with the same value in a column into one group. The aggregate then gives one answer per group.

SELECT Dept, SUM(Salary), COUNT(*) FROM emp GROUP BY Dept;
DeptSUM(Salary)COUNT(*)
IT1500003
HR300002
Sales350001

Rule: every column in SELECT that is not inside an aggregate should be in GROUP BY.

HAVING vs WHERE

SELECT Dept, COUNT(*) FROM emp GROUP BY Dept HAVING COUNT(*) > 1;     -- IT 3, HR 2
SELECT Dept, AVG(Salary) FROM emp WHERE Salary > 32000 GROUP BY Dept;  -- IT 50000, Sales 35000
WHEREHAVING
filters single rowsfilters groups
runs before GROUP BYruns after GROUP BY
cannot use aggregatesusually uses aggregates

ORDER BY

SELECT * FROM emp ORDER BY Salary;             -- ASC (small → big), default
SELECT * FROM emp ORDER BY Salary DESC;        -- big → small
SELECT * FROM emp ORDER BY Dept, Salary DESC;  -- by Dept, then Salary inside each Dept
SELECT Dept, SUM(Salary) FROM emp GROUP BY Dept ORDER BY SUM(Salary) DESC;

In ascending order NULL comes first in MySQL. The full order of clauses is: SELECT … FROM … WHERE … GROUP BY … HAVING … ORDER BY …

Equi-join on two tables

A join combines rows of two tables. An equi-join uses an equals sign on a common column. Table dept: (IT, Floor 3), (HR, Floor 1), (Sales, Floor 2).

SELECT E.Name, D.Floor
FROM emp E, dept D
WHERE E.Dept = D.Dept;

-- same with JOIN … ON
SELECT emp.Name, dept.Floor FROM emp JOIN dept ON emp.Dept = dept.Dept;

E and D are short aliases for the table names. When both tables have a column with the same name, write table.column. Without the WHERE condition you get a Cartesian product: every row with every row (6 × 3 = 18 rows). The equi-join keeps only the 6 matching pairs. Both tables' Dept column appears if you use SELECT *.

Try it: your family's spending

Write 10 things your family bought this week in a table: Item, Category (Food, Travel, School), Amount. Leave one Amount blank (NULL). Predict, then run: COUNT(*) vs COUNT(Amount), SUM by Category, categories HAVING SUM(Amount) > 500, and ORDER BY SUM(Amount) DESC. Compare the piles with step 3 and step 4 of the 3D.

Key formulas and definitions

Worked examples

1. Using emp, find the output of SELECT COUNT(*), COUNT(Salary), AVG(Salary) FROM emp;

6, 5, 43000. COUNT(*) counts Kabir's NULL row; AVG = 215000 ÷ 5.

2. Show each department with its highest salary.

SELECT Dept, MAX(Salary) FROM emp GROUP BY Dept; → IT 60000, HR 30000, Sales 35000.

3. Show departments whose average salary is more than 40000.

SELECT Dept, AVG(Salary) FROM emp GROUP BY Dept HAVING AVG(Salary) > 40000; → IT 50000. (HR average is 30000, NULL skipped.)

4. List employees from highest to lowest salary.

SELECT Name, Salary FROM emp ORDER BY Salary DESC; → Neha, Asha, Mohan, Zoya, Ravi, Kabir (NULL comes last in DESC).

5. Count employees earning more than 32000 in each department, showing only departments with at least 2 such employees.

SELECT Dept, COUNT(*) FROM emp WHERE Salary > 32000 GROUP BY Dept HAVING COUNT(*) >= 2; → IT 3.

6. Show every employee's Name with the Floor of their department.

SELECT E.Name, D.Floor FROM emp E, dept D WHERE E.Dept = D.Dept; → Asha 3, Ravi 1, Mohan 3, Zoya 2, Kabir 1, Neha 3.

7. emp has 6 rows and dept has 3 rows. How many rows does SELECT * FROM emp, dept; return?

No join condition → Cartesian product: 6 × 3 = 18 rows.

Common mistakes

Practice quiz

1. Which function counts rows including NULL values?
2. Which clause filters groups?
3. ORDER BY Salary DESC shows:
4. AVG of 10, 20 and NULL is:
5. An equi-join matches rows where the common column is:

Practice: answer these yourself

Type or choose your answer, then press Check. Use a hint if you are stuck; the full solution appears after you answer.

Frequently asked questions

What is the difference between COUNT(*) and COUNT(column)?

COUNT(*) counts every row; COUNT(column) counts only rows where that column is not NULL.

What is the difference between WHERE and HAVING?

WHERE filters individual rows before grouping and cannot use aggregates; HAVING filters groups after GROUP BY and usually uses aggregates.

What is an equi-join?

A join that combines two tables by matching rows where a common column has equal values, e.g. WHERE A.id = B.id.

Where this is taught

CBSE (India)Class 12Database Query using SQL

Learn first

Learn next

Related lessons

All Informatics Practices lessons