Difficulty: Beginner
Estimated time: 10–15 minutes
SQL concepts: GROUP BY, HAVING, filtering aggregated results
Goal: Learn the difference between filtering rows (WHERE) and filtering groups (HAVING).
The Scenario
After your “products per category” report, the product manager asks a follow-up:
“Show me only the categories that have at least 2 products.”
You already know how to count products per category using GROUP BY.
Now you need to filter the grouped results based on the count.
That’s exactly what HAVING is for.
Database Table
products
| column_name | type | description |
|---|---|---|
| product_id | INTEGER | Unique product ID |
| name | TEXT | Product name |
| category | TEXT | Product category |
| price | DECIMAL | Product price |
| stock_qty | INTEGER | Units in stock |
| created_at | TIMESTAMP | When the product was created |
Sample Data (for context)
| product_id | name | category | price |
|---|---|---|---|
| 101 | Wireless Mouse | Accessories | 24.99 |
| 102 | Mechanical Keyboard | Accessories | 89.00 |
| 103 | 27-inch Monitor | Displays | 229.99 |
| 104 | USB-C Hub | Accessories | 34.50 |
| 105 | Laptop Stand | Workspace | 39.99 |
Your Task
Write a SQL query that returns:
categorytotal_products
…but only for categories where the number of products is 2 or more.
Expected Output
| category | total_products |
|---|---|
| Accessories | 3 |
(With the sample data, only Accessories has 2+ products.)
Constraints
- Use
GROUP BY - Use
COUNT()to calculate totals - Filter groups using
HAVING - Do not use
WHEREto filter the grouped totals
Hint (Optional)
WHEREfilters rows before groupingHAVINGfilters groups after grouping
If you need to filter on an aggregate like COUNT(*), you almost always need HAVING.
SELECT
category,
COUNT() AS total_products FROM products GROUP BY category HAVING COUNT() >= 2;
Explanation
GROUP BY categoryforms one group per category.COUNT(*)counts how many rows are in each group.HAVING COUNT(*) >= 2keeps only the groups that meet the requirement.
Common Mistakes
- Using
WHEREwith an aggregateWHERE COUNT(*) >= 2 -- ❌ not valid - Placing
HAVINGbeforeGROUP BY - Confusing
WHEREandHAVINGWHEREfilters raw rowsHAVINGfilters aggregated groups
Optional Extension (Mini Bonus)
Try:
- Show categories where the average price is above 50.
- Show categories with at least 2 products, then sort by total_products descending.
- Combine
WHERE+GROUP BY+HAVING:- Count products per category only for products priced above 20
- Then show only categories with at least 2 products
Next Challenge
Beginner Challenge #8: Join Two Tables with INNER JOIN
🔗 View reference solution on GitHub
(After you’ve tried the challenge)
Want more practical SQL challenges?
Subscribe to the Solve With SQL newsletter and get new problems delivered to your inbox.