Skip to the page
Tecyfy

SQL interview question · medium

A manager asks for the average order value across all regions. You have a table with each region's average order value, so you average those. The number is wrong. Why, and what is the right query?

The short answerAn average of averages gives every region the same weight, however many orders it has.

The full answer

An average of averages gives every region the same weight, however many orders it has. A region with 50 orders counts as much as one with 50,000. The overall average is total revenue divided by total orders, which you get either from the raw orders or by keeping each region's sum and count instead of its average.

A small example

RegionOrdersRevenueAverage
North10,000500,00050
South10020,000200

Average of averages: (50 + 200) / 2 = 125. True average: 520,000 / 10,100 = about 51.5.

The small, expensive region pulls the simple average far from what a typical order is worth.

The right query

From the raw table:

SELECT SUM(amount) / COUNT(*) AS avg_order_value
FROM orders
WHERE created_at >= '2026-09-01' AND created_at < '2026-10-01';

or simply AVG(amount). From a summary table, store sums and counts, never only averages:

SELECT SUM(revenue) / SUM(order_count) AS avg_order_value
FROM region_summary;

The same mistake in other forms

  • Rates. Averaging each region's conversion rate is wrong for the same reason. Add up conversions and visits, then divide.
  • Percent change. Averaging each region's growth percentage is not the overall growth.
  • Summary tables built for one dashboard. A table with only avg_order_value per region cannot answer any other question correctly. Keep additive columns (sums and counts) so they can be rolled up.

When an unweighted average is right

Sometimes it is the question: "how does a typical region perform?" gives each region one vote, deliberately. Say which one you are reporting, and name the metric so nobody confuses the two.

A note on NULLs

AVG and SUM ignore NULLs, while COUNT(*) counts every row. SUM(amount) / COUNT(*) and AVG(amount) differ if some amounts are NULL. Decide whether a NULL amount is a free order or missing data, and filter or fill it explicitly. And if the columns are integers, SUM(x) / COUNT(*) truncates: 5 / 2 gives 2. Cast one side to numeric first.

What interviewers want: weighting, total over total instead of averaging ratios, storing additive measures in summary tables, and knowing when the unweighted version is the actual question.

Last updated 16 October 2026