Part 6: Mastering the HAVING Command

Part 6: Mastering the HAVING Command | SQL Challenges & Capstone
SQL Challenges & Capstone · Part 6 · Lecture Notes

Mastering the HAVING Command

How to filter grouped results after aggregation β€” applying business thresholds to summarized data and identifying meaningful categories.

Part 6 of 6100% Complete
HAVING
WHERE vs HAVING
Aggregation Conditions
8 Practice Questions

Learning Objectives

  • Understand how HAVING differs from WHERE β€” HAVING filters groups after aggregation
  • Apply HAVING with COUNT(), SUM(), and AVG() to filter grouped summaries
  • Use HAVING to apply business thresholds to categorized data
  • Identify the correct full clause order: SELECT β†’ FROM β†’ WHERE β†’ GROUP BY β†’ HAVING β†’ ORDER BY β†’ LIMIT
Click any section header to open or close it

HAVING filters grouped results after aggregation has been applied. While WHERE filters individual rows before grouping, HAVING filters the grouped summaries that GROUP BY produces. The distinction is critical: WHERE cannot reference aggregated values; HAVING can.

In industry, analysts use HAVING to identify high-value customers, isolate top-performing products, detect low-performing categories, apply business thresholds to summarized data, and filter reports to only meaningful groups.

WHERE vs HAVING β€” The Key Difference

WHERE filters rows before they are grouped β€” it cannot see aggregated values. HAVING filters groups after aggregation β€” it works on the summary output. If you try to use WHERE SUM(amount) > 500, the query will fail. That condition belongs in HAVING.

Basic HAVING Syntax
SELECT column_name, AGG_FUNCTION(column_name) FROM table_name GROUP BY column_name HAVING condition;

HAVING evaluates each group summary and keeps only the groups that meet the condition. Every WHERE filter condition you have learned β€” =, !=, >, <, BETWEEN β€” can also be used in HAVING, but applied to aggregated values instead of row values.

Reading a HAVING Query

Work through it in order: FROM identifies the table, GROUP BY forms the groups, the aggregation function calculates each group’s summary, then HAVING applies the filter to keep only the groups that pass. Only then does SELECT format the output.

Countries With More Than 1 User
SELECT country, COUNT(*) AS total_users FROM users GROUP BY country HAVING COUNT(*) > 1;

HAVING is the tool that turns raw aggregated data into actionable business intelligence. By setting thresholds on grouped metrics β€” revenue above a level, order counts above a minimum, average price above a benchmark β€” analysts can identify which categories, customers, or products meet meaningful business criteria.

Common Business Thresholds

HAVING SUM(amount) > 500 β€” transaction types generating significant revenue. HAVING COUNT(*) > 2 β€” statuses with multiple records. HAVING AVG(unit_price) > 50 β€” categories priced above a benchmark. HAVING SUM(line_total) > 100 β€” products with meaningful sales volume.

Transaction Types Generating Over 500
SELECT transaction_type, ROUND(SUM(amount), 2) AS total_amount FROM transactions GROUP BY transaction_type HAVING SUM(amount) > 500;
Products With Significant Sales Volume
SELECT product_id, ROUND(SUM(line_total), 2) AS total_sales FROM order_items GROUP BY product_id HAVING SUM(line_total) > 100;

Work through each question below. Run your query first, then use Check Answer. A wrong answer reveals the correct SQL with a Copy button; a correct result earns a congratulations message.

Practice 1 Show countries with more than 1 user
AI Prompt
Write a MySQL query to count users by country and show only countries with more than 1 user.
SQL Answer
SELECT country, COUNT(*) AS total_users FROM users GROUP BY country HAVING COUNT(*) > 1;
Practice 2 Show transaction types with total amount greater than 500 rounded to 2 decimal places
AI Prompt
Write a MySQL query to calculate total transaction amount by transaction_type and show only values greater than 500 rounded to 2 decimal places.
SQL Answer
SELECT transaction_type, ROUND(SUM(amount), 2) AS total_amount FROM transactions GROUP BY transaction_type HAVING SUM(amount) > 500;
Practice 3 Show products with total sales greater than 100 rounded to 2 decimal places
AI Prompt
Write a MySQL query to calculate total sales by product_id and show only products with total sales greater than 200 rounded to 2 decimal places.
SQL Answer
SELECT product_id, ROUND(SUM(line_total), 2) AS total_sales FROM order_items GROUP BY product_id HAVING SUM(line_total) > 100;
Practice 4 Show order statuses with more than 2 orders
AI Prompt
Write a MySQL query to count orders by order_status and show only statuses with more than 2 orders.
SQL Answer
SELECT order_status, COUNT(*) AS total_orders FROM orders GROUP BY order_status HAVING COUNT(*) > 2;
Practice 5 Show categories with average product price greater than 50 rounded to 2 decimal places
AI Prompt
Write a MySQL query to calculate average product price by category and show only categories with average price greater than 50 rounded to 2 decimal places.
SQL Answer
SELECT category, ROUND(AVG(unit_price), 2) AS avg_price FROM products GROUP BY category HAVING AVG(unit_price) > 50;
Practice 6 Show subscription statuses with total monthly_fee greater than 300 rounded to 2 decimal places
AI Prompt
Write a MySQL query to calculate total monthly_fee by status and show only totals greater than 300 rounded to 2 decimal places.
SQL Answer
SELECT status, ROUND(SUM(monthly_fee), 2) AS total_monthly_fee FROM subscriptions GROUP BY status HAVING SUM(monthly_fee) > 300;
Practice 7 Show users with total transaction amount greater than 100 rounded to 2 decimal places
AI Prompt
Write a MySQL query to calculate total transaction amount by user_id and show only totals greater than 250 rounded to 2 decimal places.
SQL Answer
SELECT user_id, ROUND(SUM(amount), 2) AS total_amount FROM transactions GROUP BY user_id HAVING SUM(amount) > 250;
Practice 8 Show ticket statuses with more than 1 support ticket
AI Prompt
Write a MySQL query to count support tickets by ticket_status and show only statuses with more than 1 ticket.
SQL Answer
SELECT ticket_status, COUNT(*) AS total_tickets FROM support_tickets GROUP BY ticket_status HAVING COUNT(*) > 1;

Knowledge Check

Five questions β€” select the best answer for each.

1. What is the key difference between WHERE and HAVING?
AWHERE is used with GROUP BY; HAVING is used with ORDER BY
BWHERE filters rows before grouping; HAVING filters grouped summaries after aggregation
CWHERE works with numbers; HAVING works with text
DWHERE and HAVING do the same thing β€” they are interchangeable
2. Which query correctly shows only countries with more than 1 user?
ASELECT country, COUNT(*) FROM users WHERE COUNT(*) > 1 GROUP BY country;
BSELECT country, COUNT(*) FROM users GROUP BY country HAVING COUNT(*) > 1;
CSELECT country FROM users HAVING COUNT(*) > 1;
DSELECT country, COUNT(*) FROM users HAVING country > 1 GROUP BY country;
3. Where does HAVING appear in the SQL clause order?
ABefore WHERE
BAfter SELECT but before FROM
CAfter GROUP BY
DAfter LIMIT
4. An analyst wants to find products where total sales exceed 200. Which clause should they use?
AWHERE SUM(line_total) > 200
BHAVING line_total > 200
CHAVING SUM(line_total) > 200
DWHERE line_total > 200 GROUP BY product_id
5. Which HAVING condition finds transaction types where the average amount exceeds 100?
AHAVING amount > 100
BHAVING AVG(amount) > 100
CWHERE AVG(amount) > 100
DHAVING COUNT(amount) > 100

Part 6 Summary

The key ideas from this lecture β€” keep these in mind as you move forward.

HAVING filters grouped business summaries so analysts can focus on meaningful categories and threshold-based insights. WHERE filters individual rows before grouping. HAVING filters group summaries after aggregation. The full clause order is: SELECT β†’ FROM β†’ WHERE β†’ GROUP BY β†’ HAVING β†’ ORDER BY β†’ LIMIT.

HAVINGWHERE vs HAVINGGROUP BYAggregation FilterBusiness ThresholdCOUNT()SUM()AVG()Clause Order