Skip to content
Laviyx Learn

Try

SQL course menu

SQL AVG(): Calculate the Average of a Column

Learn the SQL AVG function: average a column, average per group, round the result, compare rows to the average with a subquery, and understand how NULLs and integer types change the answer.

Beginner6 min readUpdated
On this page

AVG returns the average (the arithmetic mean) of a column: the total divided by how many values there are. Average salary, average order value, average rating.

The example table#

idnamedepartmentsalarymanager_id
1AshaSales520005
2RaviEngineering780003
3MeeraEngineering81000NULL
4JohnMarketing460005
5PriyaSales61000NULL

Average of a column#

SQLRun
SELECT AVG(salary) AS avg_salary
FROM employees;
Output
avg_salary
----------
63600

That is 318,000 ÷ 5. Depending on the database, you may see 63600.0000 or more decimal places.

Average per group#

SQLRun
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
ORDER BY avg_salary DESC;
Output
department  | avg_salary
------------+-----------
Engineering | 79500
Sales       | 56500
Marketing   | 46000

Rounding the result#

Averages often have long decimals. ROUND(value, digits) tidies them:

SQLRun
SELECT category, ROUND(AVG(price), 2) AS avg_price
FROM products
GROUP BY category
ORDER BY avg_price DESC;
Output
category    | avg_price
------------+----------
Electronics | 23166.67
Furniture   | 5750
Stationery  | 60

Electronics averages (55,000 + 2,500 + 12,000) ÷ 3 = 23,166.666…, rounded to 23,166.67.

Rows above the average#

You cannot write WHERE salary > AVG(salary), because aggregates are not allowed in WHERE. Calculate the average in a subquery instead:

SQLRun
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
Output
name  | salary
------+-------
Ravi  | 78000
Meera | 81000

The inner query runs first and returns 63,600; the outer query then keeps salaries above it.

AVG ignores NULLs#

This is the most important detail. AVG divides by the number of non-NULL values, not the number of rows:

SQLRun
SELECT AVG(manager_id) AS avg_mgr,
       SUM(manager_id) * 1.0 / COUNT(*) AS over_all_rows
FROM employees;
Output
avg_mgr | over_all_rows
--------+--------------
4.33    | 2.6

AVG used (5 + 3 + 5) ÷ 3. Dividing by all 5 rows treats the two NULLs as zeros, which gives a different answer. Neither is wrong; decide which you mean. If missing values should count as zero, write AVG(COALESCE(column, 0)).

(manager_id is an id, so averaging it is only useful as an illustration. The same effect matters a lot for columns like rating or bonus.)

Integer averages#

In SQL Server, AVG of an integer column returns an integer, dropping the decimals: the average of 1 and 2 is 1. Convert first: AVG(CAST(score AS DECIMAL(10, 2))). PostgreSQL, MySQL and SQLite return decimals automatically.

Average vs median#

The average is pulled up or down by extreme values. If nine people earn 30,000 and one earns 3,000,000, the average is 327,000, which describes nobody. The median (the middle value) is often a better "typical" figure; PostgreSQL and Oracle compute it with PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary).

Common mistakes#

Practice#

Practice exercise

Using the orders table (amounts 250, 120, 560 and 90), find the average order amount, rounded to 2 decimal places. Then list the orders that are below that average.

Show hint

ROUND(AVG(amount), 2) for the first query. For the second, compare amount with a subquery.

Show solution
SQLRun
SELECT ROUND(AVG(amount), 2) AS avg_order
FROM orders;
Output
avg_order
---------
255
SQLRun
SELECT order_id, amount
FROM orders
WHERE amount < (SELECT AVG(amount) FROM orders);
Output
order_id | amount
---------+-------
101      | 250
102      | 120
104      | 90

(250 + 120 + 560 + 90) ÷ 4 = 255. Only order 103 is above it. The average is shown as 255.00 in databases that keep the decimals.

Key takeaway#

Finished this lesson?