Aggregate Functions

Use COUNT, SUM, AVG, MIN, and MAX to analyze data.

18 min read
Beginner

Introduction to Aggregate Functions

So far, you've worked with individual rows - selecting them, filtering them, sorting them. But what if you want to answer questions like:

  • "How many products do we have?"
  • "What's the average price?"
  • "What's our total revenue?"
  • "Who's the highest-paid employee?"

You need to calculate statistics across multiple rows. That's what aggregate functions do - they take multiple values and return a single summary result.

A function that performs a calculation on a set of rows and returns a single value. Examples: COUNT, SUM, AVG, MIN, MAX.

Common Aggregate Functions
Function
Purpose
Example Result
COUNT()Counts the number of rows100
SUM()Adds up numeric values15000.50
AVG()Calculates average75.25
MIN()Finds the minimum value10
MAX()Finds the maximum value999

Let's work with our products and orders tables:

products
id
product_name
category
price
stock
1LaptopElectronics999.9945
2MouseElectronics29.99120
3Desk ChairFurniture199.9930
4MonitorElectronics349.9960
5Desk LampFurniture39.9985
6KeyboardElectronics79.9995

COUNT - Counting Rows

COUNT() returns the number of rows that match a criteria.

COUNT(*) - Count all rows:

sql
-- How many products do we have?
SELECT COUNT(*) AS total_products
FROM products;

COUNT(*) counts every row, including those with NULL values.

COUNT with WHERE - Conditional counting:

sql
-- How many Electronics products?
SELECT COUNT(*) AS electronics_count
FROM products
WHERE category = 'Electronics';

Only rows matching the WHERE condition are counted.

COUNT(column) - Count non-NULL values:

products_with_discount
id
product_name
price
discount
1Laptop999.99NULL
2Mouse29.995.00
3Desk Chair199.99NULL
4Monitor349.9920.00
5Keyboard79.9910.00
sql
-- How many products have a discount?
SELECT COUNT(discount) AS products_with_discount
FROM products_with_discount;

COUNT(discount) only counts rows where discount is not NULL. Out of 5 products, only 3 have discounts.

Comparison:

sql
-- Compare COUNT(*) vs COUNT(column)
SELECT
  COUNT(*) AS total_rows,
  COUNT(discount) AS rows_with_discount,
  COUNT(*) - COUNT(discount) AS rows_without_discount
FROM products_with_discount;

COUNT(DISTINCT) - Counting Unique Values

COUNT(DISTINCT column) counts the number of unique (different) values, excluding duplicates.

sql
-- How many different categories?
SELECT COUNT(DISTINCT category) AS category_count
FROM products;

We have 6 products but only 2 unique categories (Electronics and Furniture).

COUNT vs COUNT(DISTINCT):

sql
SELECT
  COUNT(category) AS total_categories,
  COUNT(DISTINCT category) AS unique_categories
FROM products;

SUM - Adding Up Values

SUM() adds up all numeric values in a column.

sql
-- Total value of all inventory
SELECT SUM(price * stock) AS total_inventory_value
FROM products;

This calculates: (999.99 × 45) + (29.99 × 120) + (199.99 × 30) + (349.99 × 60) + (39.99 × 85) + (79.99 × 95) = 78,449.20

SUM with WHERE:

sql
-- Total stock quantity for Electronics
SELECT SUM(stock) AS total_electronics_stock
FROM products
WHERE category = 'Electronics';

45 + 120 + 60 + 95 = 320 units of Electronics in stock.

SUM ignores NULL values:

sql
-- Sum of discounts (NULLs are skipped)
SELECT SUM(discount) AS total_discounts
FROM products_with_discount;

5.00 + 20.00 + 10.00 = 35.00. The two NULL discounts are ignored.

AVG - Calculating Averages

AVG() calculates the average (mean) of numeric values.

sql
-- Average product price
SELECT AVG(price) AS average_price
FROM products;

(999.99 + 29.99 + 199.99 + 349.99 + 39.99 + 79.99) ÷ 6 = 283.32

AVG with WHERE:

sql
-- Average price of Furniture
SELECT AVG(price) AS avg_furniture_price
FROM products
WHERE category = 'Furniture';

(199.99 + 39.99) ÷ 2 = 119.99

AVG ignores NULL values:

sql
-- Average discount (only counts non-NULL)
SELECT AVG(discount) AS avg_discount
FROM products_with_discount;

(5.00 + 20.00 + 10.00) ÷ 3 = 11.67

Note: It divides by 3 (number of non-NULL values), not 5 (total rows)!

MIN and MAX - Finding Extremes

MIN() returns the smallest value, MAX() returns the largest value.

sql
-- Cheapest and most expensive products
SELECT
  MIN(price) AS cheapest,
  MAX(price) AS most_expensive
FROM products;

MIN/MAX work with text and dates too:

sql
-- First and last product alphabetically
SELECT
  MIN(product_name) AS first_alphabetically,
  MAX(product_name) AS last_alphabetically
FROM products;
employees
id
name
department
salary
hire_date
1AliceEngineering850002020-03-15
2BobMarketing650002021-07-22
3CharlieEngineering950002019-11-03
4DianaSales700002022-01-10
sql
-- Earliest and most recent hire dates
SELECT
  MIN(hire_date) AS oldest_employee,
  MAX(hire_date) AS newest_employee
FROM employees;

Charlie was hired earliest (2019), Diana most recently (2022).

MIN/MAX with WHERE:

sql
-- Salary range for Engineering department
SELECT
  MIN(salary) AS min_eng_salary,
  MAX(salary) AS max_eng_salary
FROM employees
WHERE department = 'Engineering';

Combining Multiple Aggregates

You can use multiple aggregate functions in the same query:

sql
-- Complete product statistics
SELECT
  COUNT(*) AS total_products,
  SUM(stock) AS total_units,
  AVG(price) AS avg_price,
  MIN(price) AS cheapest,
  MAX(price) AS most_expensive,
  SUM(price * stock) AS total_value
FROM products;

Department salary analysis:

sql
-- Engineering department salary stats
SELECT
  COUNT(*) AS employees,
  MIN(salary) AS min_salary,
  MAX(salary) AS max_salary,
  AVG(salary) AS avg_salary,
  SUM(salary) AS total_payroll
FROM employees
WHERE department = 'Engineering';

Aggregate Functions with Expressions

You can use calculations inside aggregate functions:

sql
-- Total revenue if we sold all inventory
SELECT
  SUM(price * stock) AS potential_revenue,
  AVG(price * stock) AS avg_product_value
FROM products;
sql
-- Annual salary costs
SELECT
  SUM(salary * 12) AS annual_payroll,
  AVG(salary * 12) AS avg_annual_salary
FROM employees;

ROUND - Formatting Aggregate Results

Aggregate functions often return many decimal places. Use ROUND() to format results:

sql
-- Round average price to 2 decimal places
SELECT
  ROUND(AVG(price), 2) AS avg_price,
  ROUND(AVG(stock), 0) AS avg_stock
FROM products;

ROUND(value, decimals):

  • ROUND(AVG(price), 2) rounds to 2 decimal places
  • ROUND(AVG(stock), 0) rounds to nearest integer

Aggregates Return NULL on Empty Sets

What happens when there are no matching rows?

sql
-- No products in "Clothing" category
SELECT
  COUNT(*) AS count,
  SUM(price) AS sum_price,
  AVG(price) AS avg_price,
  MIN(price) AS min_price,
  MAX(price) AS max_price
FROM products
WHERE category = 'Clothing';

Important:

  • COUNT returns 0 (there are zero rows)
  • SUM, AVG, MIN, MAX return NULL (there's no data to aggregate)

Use COALESCE to provide default values for NULL results:

SELECT COALESCE(SUM(price), 0) AS total
FROM products
WHERE category = 'Clothing';

This returns 0 instead of NULL when there are no matching rows.

Common Mistakes to Avoid

Don't make these mistakes:

  1. Mixing aggregate and non-aggregate columns: ❌

    • Wrong: SELECT product_name, AVG(price) FROM products;
    • This fails because product_name is a single row, AVG(price) is one value
    • Fix: Use GROUP BY (covered in next lesson!)
  2. Using aggregate functions in WHERE: ❌

    • Wrong: WHERE AVG(price) > 100
    • WHERE filters rows BEFORE aggregation
    • Fix: Use HAVING clause (covered later)
  3. Forgetting COUNT(*) vs COUNT(column): ❌

    • COUNT(*) counts all rows (including NULL)
    • COUNT(column) counts only non-NULL values
    • Know which one you need!
  4. Assuming AVG handles NULLs like zeros: ❌

    • AVG ignores NULL, doesn't treat it as 0
    • If you want NULLs as zeros, use: AVG(COALESCE(column, 0))
  5. Using SUM/AVG on text columns: ❌

    • SUM(product_name) is invalid
    • Only use on numeric columns
  6. Not rounding results: Not an error, but messy

    • AVG(price) might return 283.32333333333
    • Use ROUND(AVG(price), 2) for cleaner output
  7. Expecting aggregates in ORDER BY without GROUP BY: ❌

    • SELECT * FROM products ORDER BY AVG(price); doesn't make sense
    • AVG returns one value for the whole table

Practical Examples

Example 1: Inventory report

sql
-- Overall inventory statistics
SELECT
  COUNT(*) AS total_products,
  COUNT(DISTINCT category) AS categories,
  SUM(stock) AS total_units_in_stock,
  ROUND(AVG(price), 2) AS avg_price,
  MIN(stock) AS lowest_stock,
  MAX(stock) AS highest_stock
FROM products
WHERE stock > 0;

Example 2: Sales performance

orders
id
product_id
quantity
order_date
1232024-02-01
2112024-02-01
3422024-02-02
4252024-02-03
5312024-02-03
sql
-- Order summary
SELECT
  COUNT(*) AS total_orders,
  SUM(quantity) AS total_items_sold,
  ROUND(AVG(quantity), 2) AS avg_items_per_order,
  MIN(quantity) AS min_order_size,
  MAX(quantity) AS max_order_size
FROM orders;

Example 3: HR analytics

sql
-- Company-wide salary statistics
SELECT
  COUNT(*) AS total_employees,
  ROUND(AVG(salary), 2) AS avg_salary,
  MIN(salary) AS min_salary,
  MAX(salary) AS max_salary,
  MAX(salary) - MIN(salary) AS salary_range
FROM employees;

Key Takeaways

What you learned:

Aggregate functions calculate statistics across multiple rows ✅ COUNT(*) counts all rows, COUNT(column) counts non-NULL values ✅ COUNT(DISTINCT column) counts unique values ✅ SUM() adds up numeric values ✅ AVG() calculates the mean (average) ✅ MIN() and MAX() find smallest and largest values ✅ Aggregate functions ignore NULL values (except COUNT(*)) ✅ Use ROUND() to format decimal results ✅ You can combine multiple aggregates in one query ✅ Aggregates return NULL when there are no rows (except COUNT returns 0)

Coming up next: We'll learn about GROUP BY to calculate aggregates for different groups of data (e.g., average price per category, total sales per product)!

Practice Exercise: Try these queries:

  1. Count how many employees are in the Engineering department
  2. Find the total, average, min, and max salary across all employees
  3. Calculate the total value of all products (price × stock)
  4. Find the average stock level for Electronics products
  5. Count how many distinct departments exist