Aggregate functions perform a calculation on a set of values and return a single value. They are often used with the GROUP BY clause.
Common Aggregate Functions
| Function | Description | NULL Handling |
|---|---|---|
COUNT(*) | Counts all rows | Includes NULLs |
COUNT(column) | Counts non-NULL values | Excludes NULLs |
SUM(column) | Total of a numeric column | Ignores NULLs |
AVG(column) | Average value | Ignores NULLs |
MAX(column) | Highest value | Ignores NULLs |
MIN(column) | Lowest value | Ignores NULLs |
COUNT(*) vs COUNT(column)
This is a frequent interview topic:
COUNT(*)counts every row in the result set, including rows with NULL values.COUNT(column_name)counts only the rows where the specified column is not NULL.
-- Total employees = 100, those with emails = 85
SELECT COUNT(*), COUNT(email) FROM employees;
-- Result: 100, 85
GROUP BY Basics
GROUP BY groups rows that have the same values into summary rows:
SELECT department_id, COUNT(*) AS employee_count
FROM employees
GROUP BY department_id;
GROUP BY Rules
Every column in the SELECT list must either:
- Appear in the
GROUP BYclause, or - Be wrapped in an aggregate function
Violating this rule causes an error in most databases (PostgreSQL, SQL Server, Oracle). MySQL is lenient but produces unpredictable results.
The HAVING Clause
WHERE filters rows before grouping. HAVING filters groups after grouping. You cannot use aggregate functions in WHERE.
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
HAVING AVG(salary) > 70000;
GROUP BY with Multiple Columns
SELECT department_id, job_role, COUNT(*) AS count
FROM employees
GROUP BY department_id, job_role;
GROUP BY with Expressions
You can group by computed values:
SELECT YEAR(hire_date) AS hire_year, COUNT(*) AS hired
FROM employees
GROUP BY YEAR(hire_date);
Note: In some databases, you must repeat the expression in GROUP BY — you cannot use the alias.
ROLLUP and CUBE
For subtotals and grand totals, databases support extensions like ROLLUP:
SELECT department_id, job_role, SUM(salary)
FROM employees
GROUP BY ROLLUP (department_id, job_role);
Q: Difference between COUNT(*) and COUNT(column)?
A:
COUNT(*)counts every row in the result set, including rows with NULL values.COUNT(column_name)counts only the rows where the specified column is not NULL.
Q: What happens if you use non-grouped columns in SELECT?
A: In most SQL standard compliant databases (like PostgreSQL), you will get an error. Every column in the SELECT list must either be an aggregate function or be included in the GROUP BY clause.
Q: What is the purpose of the GROUP BY clause?
A: It groups rows that have the same values into summary rows, typically used with aggregate functions to find totals, averages, or counts for each group.
Q: Difference between WHERE and HAVING?
A: WHERE filters rows before grouping. HAVING filters groups after grouping. You cannot use aggregate functions in WHERE.
1. Count employees per department.
SELECT department_id, COUNT(*)
FROM employees
GROUP BY department_id;2. Find departments with more than 5 employees.
SELECT department_id, COUNT(*)
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 5;3. Find highest salary per department.
SELECT department_id, MAX(salary)
FROM employees
GROUP BY department_id;4. Find duplicate emails.
SELECT email, COUNT(email)
FROM users
GROUP BY email
HAVING COUNT(email) > 1;5. Calculate running total of sales (Using Window Function).
SELECT sale_date, amount,
SUM(amount) OVER (ORDER BY sale_date) as running_total
FROM sales;6. Average salary per department with employee count.
SELECT department_id,
COUNT(*) AS emp_count,
ROUND(AVG(salary), 2) AS avg_salary
FROM employees
GROUP BY department_id;Premium Content
Unlock GROUP BY & Aggregates and all premium lessons with a subscription.
From ₹199.99/year — See plans