By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
You’re analyzing sales data for an e-commerce company. Your boss asks: - "How many orders did we get last month?" - "What’s the average order value by product category?" - "Which region has the highest sales?"
Without aggregate functions (COUNT, SUM, AVG, MIN, MAX) and GROUP BY, you’d be stuck writing dozens of individual queries—one for each product, region, or time period. Worse, you’d miss patterns (e.g., "Why is Category X underperforming in Europe?").
COUNT
SUM
AVG
MIN
MAX
GROUP BY
Why this matters in production:- Performance: Aggregates reduce millions of rows into a few meaningful numbers. Without them, you’d pull raw data into Python/R, slowing down analysis.- Decision-making: Executives don’t care about individual rows—they want trends (e.g., "Revenue is up 12% YoY").- Debugging: If a dashboard shows "Total Sales = $0," you’ll use SUM and GROUP BY to trace where the data broke.
Real-world scenario:You inherit a legacy SQL query that calculates "daily active users" by counting rows in a logins table. It runs in 30 seconds—too slow for a real-time dashboard. You rewrite it with COUNT(DISTINCT user_id) and GROUP BY date, cutting runtime to 2 seconds.
logins
COUNT(DISTINCT user_id)
GROUP BY date
COUNT()
COUNT(*)
COUNT(column)
user_id
COUNT(user_id)
SUM()
0
COALESCE(column, 0)
AVG()
AVG(COALESCE(column, 0))
MIN()
MAX()
MAX(date)
MIN(name)
HAVING
WHERE
DISTINCT
CREATE TABLE orders ( order_id INT, customer_id INT, order_date DATE, product_id INT, category VARCHAR(50), region VARCHAR(50), amount DECIMAL(10, 2) ); -- Insert sample data INSERT INTO orders VALUES (1, 101, '2023-01-15', 1001, 'Electronics', 'North', 199.99), (2, 102, '2023-01-16', 1002, 'Clothing', 'South', 49.99), (3, 101, '2023-01-17', 1003, 'Electronics', 'North', 299.99), (4, 103, '2023-01-18', 1004, 'Furniture', 'East', 599.99), (5, 104, '2023-01-19', 1002, 'Clothing', 'West', 39.99), (6, 101, '2023-01-20', 1005, 'Electronics', 'North', 99.99);
Goal: Calculate total sales, average order value, and count of orders.
SELECT COUNT(*) AS total_orders, SUM(amount) AS total_sales, AVG(amount) AS avg_order_value, MIN(amount) AS smallest_order, MAX(amount) AS largest_order FROM orders;
Expected Output:
total_orders | total_sales | avg_order_value | smallest_order | largest_order -------------+-------------+-----------------+----------------+-------------- 6 | 1289.94 | 214.99 | 39.99 | 599.99
Goal: Break down sales by product category.
SELECT category, COUNT(*) AS order_count, SUM(amount) AS category_sales, AVG(amount) AS avg_order_value FROM orders GROUP BY category;
category | order_count | category_sales | avg_order_value ------------+-------------+----------------+---------------- Electronics | 3 | 599.97 | 199.99 Clothing | 2 | 89.98 | 44.99 Furniture | 1 | 599.99 | 599.99
Goal: Find categories with more than 2 orders.
SELECT category, COUNT(*) AS order_count FROM orders GROUP BY category HAVING COUNT(*) > 2;
category | order_count ------------+------------- Electronics | 3
Goal: Sales by region and category.
SELECT region, category, SUM(amount) AS sales FROM orders GROUP BY region, category ORDER BY region, sales DESC;
region | category | sales -------+-------------+------- East | Furniture | 599.99 North | Electronics | 599.97 South | Clothing | 49.99 West | Clothing | 39.99
Goal: Count unique customers per region.
SELECT region, COUNT(DISTINCT customer_id) AS unique_customers FROM orders GROUP BY region;
region | unique_customers -------+----------------- North | 1 South | 1 East | 1 West | 1
-- ✅ Fast: Filters first SELECT category, SUM(amount) FROM orders WHERE amount > 0 -- Filter early! GROUP BY category; `` - AvoidSELECT *withGROUP BY: Only select columns inGROUP BYor aggregates.- IndexGROUP BYcolumns: Speeds up sorting (e.g.,CREATE INDEX idx_category ON orders(category)`).
`` - Avoid
with
: Only select columns in
or aggregates.- Index
columns: Speeds up sorting (e.g.,
COALESCE
ISNULL
-- ✅ Treat NULLs as 0 SELECT AVG(COALESCE(amount, 0)) FROM orders; `` - Round decimals:ROUND(SUM(amount), 2)` to avoid floating-point weirdness.
`` - Round decimals:
SUM(amount) AS total_sales
SUM(amount)
ORDER BY sales DESC
SELECT *
COUNT(DISTINCT)
HAVING filters groups after aggregation.
"How do you count unique customers?"
COUNT(DISTINCT customer_id).
COUNT(DISTINCT customer_id)
"Why does AVG(column) return NULL?"
AVG(column)
All values in the group are NULL.
"What’s wrong with this query?" sql SELECT category, SUM(amount), customer_id FROM orders GROUP BY category;
sql SELECT category, SUM(amount), customer_id FROM orders GROUP BY category;
customer_id
ORDER BY
Challenge:Find the top 3 regions by total sales, but only include regions with more than 1 order.
Solution:
SELECT region, SUM(amount) AS total_sales FROM orders GROUP BY region HAVING COUNT(*) > 1 ORDER BY total_sales DESC LIMIT 3;
Why it works:- GROUP BY region creates groups.- HAVING COUNT(*) > 1 filters regions with >1 order.- ORDER BY total_sales DESC sorts by sales.- LIMIT 3 returns only the top 3.
GROUP BY region
HAVING COUNT(*) > 1
ORDER BY total_sales DESC
LIMIT 3
COUNT(customer_id)
AVG(amount)
MIN(date)
MAX(name)
GROUP BY category, region
HAVING SUM(amount) > 100
COALESCE(amount, 0)
⚠️ Exam Traps:- GROUP BY must include all non-aggregated columns in SELECT.- HAVING is slower than WHERE—filter early! - AVG ignores NULLs (unlike SUM).
SELECT
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.