Aggregate Functions, GROUP BY and HAVING in SQL (Class 12 Computer Science)
Updated 17 October 2026 · Fact-checked
Aggregate functions (MAX, MIN, AVG, SUM, COUNT) turn many rows into one value. GROUP BY splits the rows into groups with the same value and gives one result row per group; HAVING keeps only the groups that satisfy a condition, whereas WHERE filters individual rows before grouping.
GROUP BY makes one group per DeptID; HAVING then drops whole groups (D2, D3), while WHERE filters single rows before grouping.
Illustration drawn for QuestionBuddy.
Understand Aggregate Functions, GROUP BY and HAVING
The examples use the EMPLOYEE table of the chapter (six rows; Kiran Shah has Salary NULL).
Aggregate functions work on a column of many rows and return one value.
| Function | Meaning |
|---|---|
| MAX(col) | largest value |
| MIN(col) | smallest value |
| SUM(col) | total |
| AVG(col) | average |
| COUNT(col) | number of non-NULL values |
| COUNT(*) | number of rows, including those with NULLs |
SELECT COUNT(*), COUNT(Salary), SUM(Salary), AVG(Salary), MAX(Salary), MIN(Salary) FROM EMPLOYEE;Result: 6, 5, 241000, 48200.0000, 61000, 38000. Every function except COUNT(*) ignores NULL, so Kiran Shah is not counted by COUNT(Salary), and AVG divides 241000 by 5 (not 6). MySQL shows AVG of an INT column with four decimals. COUNT(DISTINCT City) counts different cities: 4.
GROUP BY. Rows with the same value of the grouping column form a group; the aggregate is computed for each group.
SELECT DeptID, COUNT(*), SUM(Salary) FROM EMPLOYEE GROUP BY DeptID;| DeptID | COUNT(*) | SUM(Salary) |
|---|---|---|
| D1 | 2 | 113000 |
| D2 | 2 | 38000 |
| D3 | 2 | 90000 |
Rule: every column in the SELECT list that is not inside an aggregate must appear in GROUP BY. Group order is not guaranteed unless ORDER BY is used.
HAVING. Applies a condition to groups (usually on an aggregate).
SELECT DeptID, SUM(Salary) FROM EMPLOYEE GROUP BY DeptID HAVING SUM(Salary) > 90000;Result: D1 with 113000.
WHERE versus HAVING. WHERE filters rows before grouping and cannot contain an aggregate; HAVING filters groups after grouping and normally does. The two can be combined:
SELECT DeptID, COUNT(Salary) FROM EMPLOYEE WHERE City <> 'Delhi' GROUP BY DeptID;Rows of Delhi are removed first; then each department is counted, giving D1 1, D2 1, D3 1.
Clause order. SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY.
Aggregate Functions, GROUP BY and HAVING: key facts
- Aggregate functions
MAX, MIN, SUM, AVG ignore NULL COUNT(col) counts non-NULL values COUNT(star) counts all rows COUNT(DISTINCT col) different values - Each returns one value.
- AVG with NULL
- AVG = sum of non-NULL values / number of non-NULL values | EMPLOYEE: 241000 / 5 = 48200
- NULL rows are not part of the divisor.
- GROUP BY
- One output row per group
- Non-aggregate SELECT columns must be in GROUP BY
- Group order not guaranteed without ORDER BY
- Put GROUP BY after WHERE.
- WHERE or HAVING
- WHERE: filters rows before grouping, no aggregates | HAVING: filters groups after grouping, usually with an aggregate
- Clause order: WHERE, GROUP BY, HAVING, ORDER BY.
How to answer Aggregate Functions, GROUP BY and HAVING questions
For GROUP BY output questions, make the groups on paper before evaluating anything.
- 1Apply WHERE to the table and keep the surviving rows.
- 2Group the survivors by the GROUP BY column.
- 3Compute each aggregate per group; remember that functions other than COUNT(*) skip NULL.
- 4Apply HAVING to the group results; discard groups that fail.
- 5Apply ORDER BY, then write the result with headings.
- 6Check the SELECT list: any non-aggregate column must be in GROUP BY.
Aggregate Functions, GROUP BY and HAVING in real life
The idea, met in an everyday situation. Answer the question in your own words, then compare with the model answer. The one-line hook is what to remember.
Salary by department
Suppose the accounts team wants, for each department, the number of staff and the total salary bill.
Write the query and the result for D1, D2 and D3.
Try it first, then show the solutionSolution
- Group by DeptID; use COUNT(*) and SUM(Salary).
- D2 has a NULL salary, which SUM ignores, so D2 totals 38000.
Answer: SELECT DeptID, COUNT(*), SUM(Salary) FROM EMPLOYEE GROUP BY DeptID; gives D1 2 113000, D2 2 38000, D3 2 90000.
Memory hook: Make piles first, then count each pile.
Only the big departments
Suppose the management is interested only in departments whose salary bill is above 90000.
Which clause is needed and what is the result?
Try it first, then show the solutionSolution
- The condition is on a total of a group, so HAVING SUM(Salary) > 90000.
- D1 has 113000; D3 has exactly 90000, which is not above 90000.
Answer: HAVING SUM(Salary) > 90000 returns only D1 with 113000.
Memory hook: WHERE judges each person; HAVING judges each team.
Tricks to remember Aggregate Functions, GROUP BY and HAVING
Short memory aids. Say each one aloud once, then use it on a question the same day.
COUNT(*) counts rows, COUNT(col) counts values
The star counts everybody; a column name counts only the filled cells.
Use it when: NULL questions.
WHERE before, HAVING after
WHERE works before the groups exist; HAVING works after.
Use it when: Choosing the clause.
Group columns must be listed
Anything not inside an aggregate goes into GROUP BY.
Use it when: Writing correct queries.
AVG skips NULL in the divisor
Divide by the filled cells, not by all rows.
Use it when: AVG output questions.
Aggregate Functions, GROUP BY and HAVING: solved examples
Ordered from board level to HOTS. Try each one before you open the solution.
Example 1: COUNT(*) · 1 mark · MCQBoard level
Which function counts all the rows of a table, including rows that contain NULL?
(a) COUNT(Salary) (b) COUNT(*) (c) SUM(*) (d) MAX(*)
Try it first, then show the solutionSolution
- COUNT(column) skips NULL; COUNT(*) counts every row.
Answer: (b) COUNT(*)
Example 2: Two aggregate queries · 2 marks · Short answerBoard level
Write queries on EMPLOYEE to display (i) the highest salary, (ii) the number of employees. Give the results.
Try it first, then show the solutionSolution
- (i) SELECT MAX(Salary) FROM EMPLOYEE; gives 61000. (1 mark)
- (ii) SELECT COUNT(*) FROM EMPLOYEE; gives 6. (1 mark)
Answer: (i) 61000 (ii) 6
Example 3: NULL and aggregates · 3 marks · Short answerHarder board level
Write the output of SELECT COUNT(*), COUNT(Salary), SUM(Salary), AVG(Salary) FROM EMPLOYEE; and explain the difference between the first two values.
Try it first, then show the solutionSolution
- COUNT(*) = 6 (all rows); COUNT(Salary) = 5 (Kiran Shah's NULL is skipped). (1.5 marks)
- SUM(Salary) = 52000 + 38000 + 61000 + 45000 + 45000 = 241000. (0.5 mark)
- AVG(Salary) = 241000 / 5 = 48200 (shown as 48200.0000 in MySQL). (1 mark)
Answer: 6 | 5 | 241000 | 48200.0000
Example 4: GROUP BY output · 3 marks · Short answerHarder board level
Write the output of SELECT DeptID, COUNT(*), SUM(Salary) FROM EMPLOYEE GROUP BY DeptID; and explain why D2 shows 38000.
Try it first, then show the solutionSolution
- D1: Asha Rao and Meena Iyer, count 2, sum 52000 + 61000 = 113000. (1 mark)
- D2: count 2, sum 38000 because Kiran Shah's NULL salary is ignored by SUM. (1 mark)
- D3: Joy Das and Farah Khan, count 2, sum 45000 + 45000 = 90000. (1 mark)
Answer: D1 | 2 | 113000
D2 | 2 | 38000
D3 | 2 | 90000
Example 5: Case: reports for the management · 4 marks · Case-basedHOTS / competency
Suppose the accounts department runs these queries on EMPLOYEE. Write the output of each.
(i) SELECT DeptID, SUM(Salary) FROM EMPLOYEE GROUP BY DeptID HAVING SUM(Salary) > 90000; (1 mark)
(ii) SELECT City, COUNT(*) FROM EMPLOYEE GROUP BY City HAVING COUNT(*) >= 2; (1 mark)
(iii) SELECT DeptID, COUNT(Salary) FROM EMPLOYEE WHERE City <> 'Delhi' GROUP BY DeptID; (1 mark)
(iv) Which of WHERE and HAVING removes rows before the groups are made? (1 mark)
Try it first, then show the solutionSolution
- (i) D1 has 113000 and D3 exactly 90000 (not above), so only D1 | 113000.
- (ii) Delhi has Asha Rao and Joy Das; Mumbai has Ravi Kumar and Farah Khan; others have one each. Output: Delhi 2, Mumbai 2.
- (iii) Delhi rows are removed. D1 keeps Meena (1 salary); D2 keeps Ravi (38000) and Kiran (NULL, not counted) giving 1; D3 keeps Farah, 1. Output: D1 1, D2 1, D3 1.
- (iv) WHERE.
Answer: (i) D1 113000 (ii) Delhi 2, Mumbai 2 (iii) D1 1, D2 1, D3 1 (iv) WHERE
Where students lose marks in Aggregate Functions, GROUP BY and HAVING
The slips examiners see most often, and what to write instead.
Mistake: Using an aggregate in WHERE
WHERE works on single rows and cannot use an aggregate.
Wrong working
WHERE SUM(Salary) > 90000
Right working
GROUP BY DeptID HAVING SUM(Salary) > 90000
Do this: Move aggregate conditions to HAVING.
Usually costs: 1 mark
Mistake: Dividing AVG by all the rows
AVG ignores NULL values both in the sum and in the count.
Wrong working
241000 / 6 = 40166.67
Right working
241000 / 5 = 48200
Do this: Count only the filled cells.
Usually costs: 1 mark
Mistake: Selecting a column not in GROUP BY
A plain column in the SELECT list must be grouped.
Wrong working
SELECT Name, COUNT(*) FROM EMPLOYEE GROUP BY DeptID;
Right working
SELECT DeptID, COUNT(*) FROM EMPLOYEE GROUP BY DeptID;
Do this: List only grouped columns and aggregates.
Usually costs: 1 mark
Exam tips
- For NULL columns, say clearly which rows an aggregate skips.
- Compute each group on the margin before writing the result.
- Show AVG as the MySQL decimal form (48200.0000), or as the plain number if the paper uses it.
- When the question says "for each", the answer needs GROUP BY.
- Use HAVING for conditions on aggregates and WHERE for conditions on single rows.
Practice questions on Aggregate Functions, GROUP BY and HAVING
Write each answer on paper first. Open the hint only if you are stuck, and the answer only when you have finished.
Q1 · 1 mark · MCQBoard level
Which clause is used to apply a condition on a group in SQL?
(a) WHERE (b) ORDER BY (c) HAVING (d) DISTINCTHint
Think of the aggregate condition.
Answer
(c) HAVING
Q2 · 1 mark · Very short answerBoard level
What is the output of SELECT MIN(DOJ) FROM EMPLOYEE;?
Hint
The earliest date is the smallest.
Answer
2017-01-20
Q3 · 3 marks · Short answerHarder board level
Write the output of SELECT DeptID, AVG(Salary) FROM EMPLOYEE GROUP BY DeptID;
Hint
AVG ignores NULL within the group.
Answer
D1 | 56500.0000
D2 | 38000.0000
D3 | 45000.0000. D1: (52000 + 61000) / 2; D2: only Ravi Kumar's 38000 counts, since Kiran Shah is NULL; D3: (45000 + 45000) / 2.Q4 · 1 mark · Assertion-reasonHarder board level
Assertion (A): AVG(Salary) of the EMPLOYEE table is 48200.
Reason (R): AVG ignores NULL values and divides by the number of non-NULL values.
(a) Both A and R are true and R is the correct explanation of A. (b) Both A and R are true but R is not the correct explanation of A. (c) A is true but R is false. (d) A is false but R is true.Hint
Sum 241000, how many values?
Answer
(a) Both are true and R explains A: 241000 / 5 = 48200.
Q5 · 3 marks · Short answerHOTS / competency
A student writes: SELECT DeptID, MAX(Salary) FROM EMPLOYEE WHERE MAX(Salary) > 50000 GROUP BY DeptID; (i) What is wrong? (ii) Rewrite it to list departments whose highest salary is above 50000, with the output.
Hint
An aggregate cannot be in WHERE.
Answer
(i) WHERE cannot contain an aggregate function; the condition is on a group. (ii) SELECT DeptID, MAX(Salary) FROM EMPLOYEE GROUP BY DeptID HAVING MAX(Salary) > 50000; Output: D1 | 61000.
Test your recall
Answer in your head or on paper first, then open the card. Pulling an answer out of memory makes it stick far better than re-reading.
1.Which aggregate functions are in the syllabus?Show answer
MAX, MIN, AVG, SUM and COUNT.
2.Does SUM count NULL as zero?Show answer
No; it ignores NULL.
3.What does COUNT(*) count?Show answer
All rows, including those with NULLs.
4.Which clause groups rows?Show answer
GROUP BY.
5.Which clause filters groups?Show answer
HAVING.
6.Which clause cannot contain an aggregate?Show answer
WHERE.
Aggregate Functions, GROUP BY and HAVING: frequently asked questions
What is the difference between WHERE and HAVING?
WHERE filters individual rows before the groups are formed and cannot use aggregates. HAVING filters whole groups after GROUP BY, usually with an aggregate.
What is the difference between COUNT(*) and COUNT(column)?
COUNT(*) counts all rows. COUNT(column) counts only the rows in which that column is not NULL.
How does AVG handle NULL?
AVG ignores NULL values: it adds the non-NULL values and divides by the number of non-NULL values.
Is the order of groups fixed in GROUP BY output?
No. Add ORDER BY if a particular order is needed.