What You Will Learn
- The five core SQL aggregation functions
- How each one handles NULL values
- Using
DISTINCTinside aggregations - How aggregations combine with WHERE
Why This Topic Matters
Every report you will ever build is built on these five functions. Total revenue = SUM. Order count = COUNT. Average delivery time = AVG. Cheapest product = MIN. Most expensive = MAX. Master them now and the rest of SQL becomes much easier — especially GROUP BY in lesson 21, which is just aggregations applied per group.
The Five Functions
| Function | What it returns | Example |
|---|---|---|
| COUNT | Number of rows | COUNT(*) |
| SUM | Total of numeric values | SUM(amount) |
| AVG | Average (mean) of numeric values | AVG(amount) |
| MIN | Smallest value | MIN(amount) |
| MAX | Largest value | MAX(amount) |
Sample Data
We extend our orders table with one more column, delivery_min, and one NULL row:
| order_id | customer | amount | delivery_min |
|---|---|---|---|
| 001 | Anita | 500 | 32 |
| 002 | Ravi | 1200 | 47 |
| 003 | Mira | 750 | NULL |
| 004 | Sam | 900 | 28 |
| 005 | Anita | 1500 | 52 |
COUNT — How Many Rows?
SELECT COUNT(*) FROM orders; → 5 (counts all rows)
SELECT COUNT(amount) FROM orders; → 5 (counts non-NULL amount values)
SELECT COUNT(delivery_min) FROM orders; → 4 (skips the NULL!)
COUNT(*) counts every row, including rows with NULLs. COUNT(column_name) counts only non-NULL values in that column. This difference bites beginners constantly.
COUNT(DISTINCT ...) — Unique Values
SELECT COUNT(DISTINCT customer) FROM orders; → 4 (Anita, Ravi, Mira, Sam)
SELECT COUNT(DISTINCT city) FROM orders; → 3 (Mumbai, Chennai, Kolkata)
Useful for "how many unique customers placed an order?"
SUM — Total of a Numeric Column
SELECT SUM(amount) FROM orders; → 4850
SELECT SUM(delivery_min) FROM orders; → 159 (ignores the NULL row)
SUM automatically ignores NULLs — they do not contribute 0, they are skipped. If you SUM a column where every value is NULL, the result is NULL (not 0).
AVG — Average of Non-NULL Values
SELECT AVG(delivery_min) FROM orders; → 39.75 (159 / 4, not 159 / 5)
This is a critical point: AVG ignores NULLs entirely. It does not treat them as 0. The denominator is the count of non-NULL values, not the count of all rows.
If you wanted "average delivery time including orders that have no recorded time as 0", you would write:
SELECT AVG(COALESCE(delivery_min, 0)) FROM orders; → 31.8 (159 / 5)
COALESCE(delivery_min, 0) replaces NULL with 0 before averaging. Whether that is the right thing to do depends on the business question — usually it is not, because missing data is not the same as zero.
MIN and MAX — Smallest and Largest
SELECT MIN(amount) FROM orders; → 500
SELECT MAX(amount) FROM orders; → 1500
SELECT MIN(delivery_min) FROM orders; → 28 (ignores NULL)
SELECT MAX(delivery_min) FROM orders; → 52
MIN and MAX work on dates too:
SELECT MIN(ordered_at) AS first_order,
MAX(ordered_at) AS latest_order
FROM orders;
Multiple Aggregations in One Query
You can compute several at once:
SELECT
COUNT(*) AS order_count,
SUM(amount) AS total_revenue,
AVG(amount) AS avg_order_value,
MIN(amount) AS smallest_order,
MAX(amount) AS largest_order
FROM orders;
Result:
| order_count | total_revenue | avg_order_value | smallest_order | largest_order |
|---|---|---|---|---|
| 5 | 4850 | 970 | 500 | 1500 |
One query, five numbers. This is the foundation of every "summary" report.
Combining Aggregations with WHERE
WHERE filters before the aggregation runs. So this:
SELECT SUM(amount) AS mumbai_revenue
FROM orders
WHERE city = 'Mumbai';
First filters to Mumbai rows, then sums them. Result: 500 + 1500 = 2000.
The Aggregate Without GROUP BY Trap
When you use an aggregate function without GROUP BY, the entire result is one row — even if the query also selects a non-aggregated column. This:
SELECT customer, SUM(amount)
FROM orders;
Returns one row in strict SQL (most databases reject this; SQLite returns the first customer with the total sum — misleading). The fix is GROUP BY, which we cover in lesson 21.
NULL Handling Summary
| Function | Behavior on NULL |
|---|---|
| COUNT(*) | Counts every row, NULL or not |
| COUNT(column) | Skips NULL values in that column |
| SUM | Skips NULL values; returns NULL if all values are NULL |
| AVG | Skips NULL values; denominator = non-NULL count |
| MIN, MAX | Skip NULL values |
Common Mistakes
- Using
COUNT(column)when you meanCOUNT(*). If the column has NULLs, you undercount rows. - Forgetting that AVG ignores NULLs. If 30% of delivery times are NULL, your "average" only reflects the 70% that were recorded — which may be a biased sample.
- Mixing aggregated and non-aggregated columns.
SELECT customer, SUM(amount) FROM ordersis invalid in most databases. Use GROUP BY. - Summing a column stored as text.
SUMsilently returns 0 or an error. Convert types first. - Confusing
COUNT(DISTINCT col)withDISTINCT COUNT(*). The latter is not valid syntax. UseCOUNT(DISTINCT col)to count unique values.
Practical Exercise (10 minutes)
Using the sample data above, write queries to compute:
- Total amount across all orders.
- Number of orders (use COUNT(*)).
- Average delivery time (ignoring NULLs).
- Smallest and largest amount.
- Number of unique customers.
- Total amount for Mumbai orders only.
- Average amount for orders placed by Anita.
Mini Challenge
Write a query that returns: total orders, total revenue, average revenue per order (computed two ways — once with AVG and once with SUM/COUNT), and the difference between them. The two averages should match if every row has an amount — but if NULLs exist, they will differ. Understanding why is the whole point of this lesson.
Key Takeaways
- Five core aggregates: COUNT, SUM, AVG, MIN, MAX.
COUNT(*)counts rows;COUNT(column)counts non-NULL values.- AVG, SUM, MIN, MAX all silently skip NULLs.
- Use
COALESCE(col, 0)if you want NULLs treated as 0 (rarely the right call). - Combine with WHERE to filter before aggregating.
Previously learned: Lessons 17–19 covered SELECT, WHERE, ORDER BY, LIMIT.
Today: You learned the five aggregation functions and how they handle NULLs.
Next: Lesson 21 puts aggregations to work with GROUP BY — the SQL version of a pivot table.
FAQ
Why does SUM return NULL instead of 0 when all values are NULL?
Because SQL cannot know whether "no values" means "the total is zero" or "we have no data". If you want 0 instead, wrap with COALESCE: COALESCE(SUM(amount), 0).
Can I use COUNT(*) and SUM(amount) in the same query?
Yes. Mixing aggregates is fine: SELECT COUNT(*), SUM(amount), AVG(amount) FROM orders; returns one row with three values. The constraint is only that you cannot mix aggregates with non-aggregated columns without GROUP BY.
Comments
Comments
Post a Comment