Last updated: August 27, 2026.
HAVING filters groups after GROUP BY. Use WHERE for individual rows before grouping and HAVING for aggregate conditions.
Basic syntax
SELECT grouping_column, aggregate_function(expression)
FROM table_name
WHERE row_condition
GROUP BY grouping_column
HAVING aggregate_condition;Filter customers by total spending
SELECT
customer_id,
COUNT(*) AS order_count,
SUM(total_amount) AS total_spent
FROM orders
WHERE order_status = 'completed'
GROUP BY customer_id
HAVING SUM(total_amount) >= 500;The WHERE clause removes incomplete orders before grouping. HAVING then keeps only customer groups whose completed-order total reaches 500.
Combine aggregate conditions
SELECT
category_id,
COUNT(*) AS product_count,
AVG(unit_price) AS average_price
FROM products
GROUP BY category_id
HAVING COUNT(*) >= 5
AND AVG(unit_price) < 100;| Clause | Filters | Evaluated |
|---|---|---|
WHERE | Individual rows | Before grouping |
HAVING | Grouped or aggregate results | After grouping |
See the PostgreSQL SELECT documentation for the formal behavior of HAVING.