DevLearningTools

LEARN · SQL

SQL Aggregate Functions

An aggregate function takes many rows and collapses them into a single summary value. Learn what makes a function an aggregate, the five core ones, and how they handle NULL, before this module covers each in depth.

Every query so far has returned one row of output per row of input, filtered or sorted, but still one-to-one. Beacon Robotics' finance team now has a different kind of question: not "show me every employee's salary," but "what's the total payroll?" or "how many employees do we have?" Those questions don't want one answer per row, they want one answer for the whole table. That's what an aggregate function is for.

Learning Objectives

  • Define what an aggregate function is and how it differs from a regular column.
  • Name the five core aggregate functions and what each one computes.
  • Understand how COUNT(*), COUNT(column), SUM, AVG, MIN, and MAX each handle NULL values.

Many Rows

Every employee's salary

Aggregate Function

SUM(), AVG(), COUNT()...

One Value

A single summary row

What Is an Aggregate Function?

An aggregate function takes a whole column of values, across many rows, and collapses them into a single summary value, a total, a count, an average, a smallest, or a largest. This is fundamentally different from every function or operator covered so far. salary * 1.10 produces one output per row, one new value for each employee. SUM(salary) produces exactly one output, period, no matter how many rows it looked at.

The Five Core Aggregate Functions

All five are standard SQL, spelled and behaving identically on MySQL, MariaDB, PostgreSQL, SQLite, SQL Server, and Oracle. This module gives each one its own full lesson; this page covers what they have in common first.

FunctionWhat It ComputesWorks on
COUNT()How many rows, or how many non-NULL valuesAny column, or *
SUM()The total of all valuesNumeric columns
AVG()The average (mean) of all valuesNumeric columns
MIN()The smallest valueNumeric, text, or date columns
MAX()The largest valueNumeric, text, or date columns

Aggregate Functions vs. Regular Columns

Notice neither query lists first_name or department, an aggregate function is already summarizing every row into one, there's nothing row-specific left to show alongside it. Mixing a raw column with an aggregate function in the same SELECT, without GROUP BY, is one of the most common mistakes beginners make here, covered below and fixed properly once GROUP BY arrives in Module 5.

MySQL / MariaDB / PostgreSQL / SQLite / SQL Server / Oracle
SELECT COUNT(*) AS employee_count
FROM employees;

SELECT SUM(salary) AS total_payroll
FROM employees;

COUNT(*) vs. COUNT(column): How NULL Is Handled

This same NULL-skipping behavior applies to SUM(), AVG(), MIN(), and MAX() too, every one of them ignores NULL values in the column entirely rather than treating NULL as zero. AVG(salary) on a table where one employee's salary is NULL divides by the number of employees that actually have a salary value, not the total row count.

COUNT(*)
  • Counts every row in the result, period.
  • A NULL value anywhere in a row doesn't stop it from being counted.
  • Answers: "how many rows are there?"
COUNT(column)
  • Counts only rows where that specific column is not NULL.
  • A row with a NULL in that column is skipped.
  • Answers: "how many rows actually have a value here?"

Try It Yourself

Write a query, portable across all six databases in this course, that returns both the total number of employees and the total payroll, in one query.

Answer
SELECT COUNT(*) AS employee_count, SUM(salary) AS total_payroll
FROM employees;

Frequently Asked Questions

Can more than one aggregate function appear in the same SELECT?

Yes, any number of aggregate functions can appear together, each computing its own single summary value from the same set of rows, exactly like the COUNT(*) and SUM(salary) example above.

Does an aggregate function filter rows, like WHERE does?

No. An aggregate function summarizes whatever rows reach it, it doesn't decide which rows those are. WHERE still runs first to narrow the rows, and the aggregate function then summarizes what's left, for example COUNT(*) FROM employees WHERE department = 'Engineering' counts only Engineering employees.

Common Beginner Mistakes

Mixing a raw column with an aggregate function, without GROUP BY

SELECT department, AVG(salary) FROM employees looks reasonable, but department is a per-row value while AVG(salary) is a single summary value, SQL doesn't know which department's name to show next to one averaged number. PostgreSQL, SQL Server, Oracle, and modern MySQL (5.7.5 and later, its default configuration) all reject this outright with an error. Older MySQL and SQLite are more lenient and may run it anyway, silently picking an arbitrary department value, which is worse than an error since it looks like a real answer. The actual fix is GROUP BY, which computes one average per department instead of one average for the whole table, covered in Module 5, don't worry about its syntax yet.

Assuming AVG() treats NULL as zero

It doesn't, NULL rows are excluded from the average entirely, not counted as zero. A column with values 100, 200, and NULL averages to 150 (300 divided by 2 non-NULL values), not 100 (300 divided by 3 rows).

Best Practices

  • Don't mix raw, non-aggregated columns with aggregate functions in the same SELECT unless GROUP BY is also present.
  • Use COUNT(*) to count rows, and COUNT(column) specifically when the goal is counting non-NULL values in that column.
  • Remember NULL is excluded, not zeroed, by SUM, AVG, MIN, and MAX, when a column might contain NULLs.

Interview Questions

What's the difference between COUNT(*) and COUNT(column_name)?

COUNT(*) counts every row returned by the query, regardless of NULLs anywhere in it. COUNT(column_name) counts only the rows where that specific column holds a non-NULL value. SELECT COUNT(*), COUNT(middle_name) FROM employees; on a table where 3 of 10 employees have a NULL middle_name returns 10 and 7 respectively.

Why does SELECT department, AVG(salary) FROM employees fail (or behave unpredictably) on most databases?

department is a per-row value, there's one for every employee, while AVG(salary) collapses all rows into a single number. The query has no way to pair one department label with one averaged number when there are many departments involved. The fix is GROUP BY department, which computes a separate average for each distinct department value instead of one average for the entire table.

Summary

An aggregate function collapses many rows into one summary value, unlike a regular column or arithmetic expression, which produces one output per row. The five core functions, COUNT, SUM, AVG, MIN, and MAX, are standard across every database in this course, and all of them (except COUNT(*)) ignore NULL values rather than treating them as zero.

What's Next?

The next lesson covers MIN() and MAX() in depth, finding the smallest and largest values in a column.

</>

Ready to Practice SQL?

Write and run real SQL queries online, right in your browser, no install or signup required. Pick a playground based on which database you want to practice on.

SQLite / PostgreSQL

Fast, no server, no ads.

Open DB Fiddle ↗

MySQL / SQL Server

Switch databases with one dropdown.

Open SQL Fiddle ↗

Both open a third-party SQL playground in a new tab. External site terms and privacy policy apply.