WHERE and HAVING
SQL · Reference cheat sheet
WHERE and HAVING
SQL · Reference cheat sheet
📋 Overview
WHERE filters rows before aggregation; HAVING filters groups after GROUP BY. Use WHERE for row predicates and HAVING for aggregate conditions (COUNT, SUM, …).
🔧 Core concepts
- Order —
FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY. - Predicates —
=,<>,<,IN,BETWEEN,LIKE/ILIKE,IS NULL. - Boolean —
AND/OR/NOT; parentheses for clarity. - Aliases —
HAVINGmay allow select aliases in some engines; don’t rely on it portably. - Sargability — avoid wrapping indexed columns in functions in
WHERE.
💡 Examples
SELECT id, email
FROM users
WHERE is_active = TRUE
AND created_at >= DATE '2026-01-01'
AND email LIKE '%@example.com';
SELECT customer_id, COUNT(*) AS order_count, SUM(total) AS revenue
FROM orders
WHERE status <> 'cancelled'
GROUP BY customer_id
HAVING COUNT(*) >= 3
AND SUM(total) > 1000;
-- Prefer WHERE over HAVING when possible
SELECT customer_id, COUNT(*) AS c
FROM orders
WHERE region = 'EU' -- row filter
GROUP BY customer_id
HAVING COUNT(*) >= 3; -- group filter-- NULL-safe checks
WHERE deleted_at IS NULL
-- NOT: WHERE deleted_at = NULL⚠️ Pitfalls
WHERE COUNT(*) > 1is invalid — aggregates belong inHAVING(or subquery).ORacross columns often disables simple index use — considerUNION.WHERE col = NULLnever matches — useIS NULL.- MySQL
ONLY_FULL_GROUP_BYrejects non-aggregated selected columns. - Filtering on
SELECTaliases inWHEREis invalid in standard SQL.