πŸŽ‰ 75% of content is free forever β€” Unlock Premium from $10/mo β†’
CW
Search courses…
πŸ’Ό Servicesℹ️ Aboutβœ‰οΈ ContactView Pricing Plansfrom $10

HAVING Clause

SQL AggregationHAVING🟒 Free Lesson

Advertisement

SQL Aggregation

HAVING Clause

Filter groups after aggregation with the HAVING clause.

  • WHERE filters rows β€” before grouping occurs
  • HAVING filters groups β€” after aggregation is complete Think of HAVING as WHERE's post-grouping partner.

What is HAVING?

WHERE vs HAVING: When Each AppliesWHERE: Filters Rows BEFORE GroupingWHERE hire_date > '2020-01-01'β†’ Removes rows first, then groups remaindersCannot use aggregate functions in WHERESpeed: Fast (reduces dataset before GROUP BY)Scope: Individual rowsHAVING: Filters Groups AFTER AggregationHAVING COUNT(*) > 5β†’ Groups first, then removes small groupsCan use aggregate functions (SUM, AVG, COUNT)Speed: Slower (runs after GROUP BY)Scope: Grouped rowsOrder: FROM β†’ WHERE β†’ GROUP BY β†’ HAVING β†’ SELECT β†’ ORDER BY
SELECT department, COUNT(*) AS employee_count
FROM employees
GROUP BY department
HAVING COUNT(*) > 5;
-- Filter departments with average salary above 60000
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 60000;
-- Using alias in HAVING
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING avg_salary > 60000;

WHERE vs HAVING

-- WHERE filters rows before grouping
SELECT department, AVG(salary) AS avg_salary
FROM employees
WHERE hire_date > '2020-01-01'
GROUP BY department
HAVING AVG(salary) > 60000;
FeatureWHEREHAVING
Applies toIndividual rowsGrouped rows
TimingBefore GROUP BYAfter GROUP BY
AggregatesCannot useCan use
PerformanceFasterSlower

Multiple Conditions in HAVING

-- Multiple HAVING conditions
SELECT department, job_title, COUNT(*) AS cnt
FROM employees
GROUP BY department, job_title
HAVING COUNT(*) > 3 AND AVG(salary) > 50000;
-- Combining OR and AND in HAVING
SELECT department, COUNT(*) AS cnt, SUM(salary) AS total
FROM employees
GROUP BY department
HAVING COUNT(*) > 5 OR SUM(salary) > 500000;

HAVING with Aggregate Functions

-- Using multiple aggregate functions in HAVING
SELECT department,
       MIN(salary) AS min_salary,
       MAX(salary) AS max_salary,
       AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING MAX(salary) - MIN(salary) > 30000;
-- HAVING with COUNT and SUM
SELECT department, COUNT(*) AS cnt, SUM(salary) AS total
FROM employees
GROUP BY department
HAVING COUNT(*) >= 10 AND SUM(salary) > 1000000;

Real-World Examples

-- Find departments with high turnover (many terminated employees)
SELECT department,
       COUNT(*) AS total_employees,
       SUM(CASE WHEN status = 'terminated' THEN 1 ELSE 0 END) AS terminated
FROM employees
GROUP BY department
HAVING SUM(CASE WHEN status = 'terminated' THEN 1 ELSE 0 END) > 3;
-- Identify products with insufficient stock
SELECT category,
       AVG(stock_quantity) AS avg_stock,
       MIN(stock_quantity) AS min_stock
FROM products
GROUP BY category
HAVING MIN(stock_quantity) < 10;

HAVING with JOIN

-- HAVING with joined tables
SELECT d.department_name, COUNT(*) AS employee_count
FROM employees e
JOIN departments d ON e.department_id = d.id
GROUP BY d.department_name
HAVING COUNT(*) > 10;
-- Complex HAVING with multiple joins
SELECT d.department_name,
       e.job_title,
       COUNT(*) AS cnt
FROM employees e
JOIN departments d ON e.department_id = d.id
JOIN salaries s ON e.id = s.employee_id
GROUP BY d.department_name, e.job_title
HAVING AVG(s.salary) > 80000 AND COUNT(*) > 5;

Common HAVING Patterns

PatternUse Case
HAVING COUNT(*) > NFind groups with minimum size
HAVING AVG(col) > NFilter by average value
HAVING SUM(col) > NFilter by total value
HAVING MIN/MAXFilter by extreme values
Multiple conditionsComplex group filtering

Need Expert SQL Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement