SQL COUNT, SUM, AVG, MIN and MAX
How many orders have we received? What is the average price of our products? What is the highest salary? Aggregate functions answer this kind of question: they take all the rows of a column and summarize them into a single value.
Syntax
SELECT COUNT(*), SUM(column), AVG(column), MIN(column), MAX(column)
FROM table;How it works
| Function | Returns |
|---|---|
COUNT(*) | the number of rows |
COUNT(column) | the number of non-NULL values |
SUM(column) | the sum |
AVG(column) | the average |
MIN(column) / MAX(column) | the smallest / largest value (also works with text and dates) |
Without GROUP BY, a query that uses an aggregate returns a single row for the whole table. To get one result per category, per city or per month, you need to add a GROUP BY (see the next lesson).
Averages often have many decimals: ROUND(AVG(prix), 2) rounds to two decimal places.
You can also combine an aggregate with a WHERE: the filter is applied before the calculation.
Diagram
| nom | prix |
|---|---|
| Clavier | 49 |
| Plaid | 25 |
| Gourde | 12 |
| SUM(prix) |
|---|
| 86 |
Simplified diagram to show the idea. The examples below use the real SQL Quest practice database (a fictional online shop: see the full schema).
Glossary: the sample database uses French names
clients- customers
commandes- orders
lignes_commande- order lines
produits- products
fournisseurs- suppliers
employes- employees
prenom / nom- first name / last name (or name)
ville- city
pays- country
prix- price
prix_unitaire- unit price
quantite- quantity
categorie- category
date_commande- order date
poste- job title
departement- department
salaire- salary
statut- status: livrée = delivered, expédiée = shipped, en cours = in progress, annulée = cancelled
Examples with their results
1. Count rows
The total number of orders.
SELECT COUNT(*) AS nb_commandes
FROM commandes; Try it in the sandbox| nb_commandes |
|---|
| 600 |
1 row in total
2. Several aggregates at once
The minimum, maximum and average price of the products.
SELECT MIN(prix) AS min, MAX(prix) AS max, ROUND(AVG(prix), 2) AS moyenne
FROM produits; Try it in the sandbox| min | max | moyenne |
|---|---|---|
| 3.7 | 342 | 56.04 |
1 row in total
3. A computed sum
The total revenue: the sum of quantity × unit price over all the order lines.
SELECT ROUND(SUM(quantite * prix_unitaire), 2) AS chiffre_affaires
FROM lignes_commande; Try it in the sandbox| chiffre_affaires |
|---|
| 241,959.75 |
1 row in total
4. Aggregate after a filter
The number of cancelled orders and the date of the first one.
SELECT COUNT(*) AS annulees, MIN(date_commande) AS premiere
FROM commandes
WHERE statut = 'annulée'; Try it in the sandbox| annulees | premiere |
|---|---|
| 92 | 2023-01-09 |
1 row in total
Common mistakes
Mixing a column and an aggregate without GROUP BY
SQLite accepts this query but shows a product name picked at random, unrelated to the total. Other databases reject it.
SELECT nom, SUM(stock) FROM produits;SELECT categorie, SUM(stock) FROM produits GROUP BY categorie;Using an aggregate in WHERE
WHERE is evaluated row by row, before any group calculation: it cannot contain COUNT or SUM. Use HAVING.
SELECT categorie FROM produits WHERE COUNT(*) > 5 GROUP BY categorie;SELECT categorie FROM produits GROUP BY categorie HAVING COUNT(*) > 5;Forgetting to round
An average often shows many decimals. Round it with ROUND.
SELECT AVG(salaire) FROM employes;SELECT ROUND(AVG(salaire), 2) FROM employes;Exercises
Try writing the query yourself before opening the solution.
Challenge 1. Compute the total payroll (sum of salaries) and the average salary rounded to the euro.
Show a solution
SELECT SUM(salaire) AS masse_salariale, ROUND(AVG(salaire)) AS salaire_moyen FROM employes;| masse_salariale | salaire_moyen |
|---|---|
| 117,900 | 4,716 |
1 row in total
Try it in the sandboxChallenge 2. What are the dates of the first and the last order?
Show a solution
SELECT MIN(date_commande) AS premiere, MAX(date_commande) AS derniere FROM commandes;| premiere | derniere |
|---|---|
| 2023-01-02 | 2025-12-28 |
1 row in total
Try it in the sandboxThe interactive exercises are checked automatically, with a tutor who explains your mistakes. A short lesson stays next to the editor.
Frequently asked questions
What is the difference between COUNT(*) and COUNT(column)?
COUNT(*) counts every row. COUNT(column) only counts the rows where the column is not NULL.
Does AVG take NULL values into account?
No: AVG averages only the known values. Like SUM, MIN and MAX, it ignores NULLs.
Can I use several aggregate functions in one query?
Yes, as many as you want in the SELECT, as in the MIN, MAX and AVG example above.