How do the aggregate functions treat NULL values, and why does that matter in practice?
Every aggregate except COUNT(*) ignores NULLs. SUM skips them, AVG skips them in both the numerator and the denominator, MIN and MAX skip them, and COUNT(column) counts only the non-NULL values. The effect is that an aggregate describes the population of values that are actually present, not the population of rows.
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL,
amount DECIMAL(10, 2)
);
INSERT INTO orders (id, customer_id, amount) VALUES
(1, 1, 120.00),
(2, 1, NULL),
(3, 1, 340.50),
(4, 2, NULL),
(5, 3, 75.25);
SELECT COUNT(*) AS rows_in_group,
COUNT(amount) AS non_null_amounts,
SUM(amount) AS total,
AVG(amount) AS average,
MIN(amount) AS smallest,
MAX(amount) AS largest
FROM orders;The results: 5 rows in the table, 3 of them with an amount, a total of 535.75, an average of 178.583333333333 — which is 535.75 divided by the three values that are actually present — a smallest of 75.25 and a largest of 340.50. The two NULL amounts contributed nothing to the sum, nothing to the average's denominator, and nothing to the minimum or maximum.
That is usually what you want, and it is why AVG(amount) is not the same as SUM(amount) / COUNT(*). The second expression divides 535.75 by 5 instead of by 3, producing 107.15 and quietly pretending there were two zero-value orders.
Where the NULL-skipping bites is when a NULL means something specific. If a missing amount means "the order was cancelled and has no value" rather than "we did not record the amount", then including those rows in a count but not in a sum is a defensible choice, but you have to make it deliberately. And if a NULL amount means the data is corrupt, then AVG silently hides the corruption and the report looks healthy.
One last detail: COUNT(*) counts rows, so it counts rows whose every column is NULL. COUNT(amount) counts values. The difference between the two numbers is exactly the number of rows with a missing value in that column, which is often the number the report is trying to surface.