On an empty input, SUM, AVG, MIN and MAX return NULL. COUNT returns 0. That difference is the reason a dashboard tile sometimes shows a blank instead of a 0.
What each one does
-- No orders on 2025-01-01 SELECT COUNT(*), COUNT(order_id), SUM(amount), AVG(amount), MAX(amount) FROM orders WHERE order_date = '2025-01-01'; -- 0, 0, NULL, NULL, NULL
There is a logic to it. Zero is a real answer to "how many". But "what is the sum of nothing" or "what is the largest of nothing" is treated as unknown, so SQL returns NULL. (Mathematically the sum of nothing is 0, but SQL chose NULL, and you have to live with it.)
One row or no rows
This is the part people miss.
- An aggregate query without GROUP BY always returns exactly one row, even over zero input rows. That is the row of NULLs and 0 above.
- An aggregate query with GROUP BY returns one row per group. With zero input rows there are zero groups, so the result is empty. No row at all.
SELECT region, SUM(amount) FROM orders WHERE order_date = '2025-01-01' GROUP BY region; -- 0 rows
So a "daily revenue by region" report quietly skips regions with no sales. To show zeros you need a list of regions to left join from.
Fixing it for reports
Wrap the aggregate: COALESCE(SUM(amount), 0). Do it at the outermost level where the value is shown. Wrapping inside, for example SUM(COALESCE(amount, 0)), only helps with NULL amounts in existing rows, not with empty sets.
Be careful with AVG. An empty AVG as NULL is honest. Turning it into 0 says "the average was zero", which is a different claim.