WHERE
Keeps only the rows for which a condition is TRUE.
Syntax
SELECT ... FROM table
WHERE condition [AND | OR condition ...];WHERE is evaluated once per row, before grouping. A row is kept only when the condition is TRUE; rows where it is FALSE or NULL (unknown) are dropped.
- Combine conditions with
AND,ORandNOT.ANDbinds tighter thanOR, soa OR b AND cmeansa OR (b AND c). Use parentheses whenever you mix them. - Compare text with single-quoted literals:
city = 'Riyadh'. Text comparison is case-sensitive. - Dates can be compared with ISO literals:
order_date >= '2025-03-01'. WHEREcannot use aggregates (SUM,COUNT) — useHAVING— and cannot use window functions or select-list aliases, because it runs before those are computed.- NULL:
col = NULLis never true. Usecol IS NULL. Andcol <> 'x'silently drops rows where col is NULL.
Examples
SELECT product_name, category, price
FROM products
WHERE category = 'Kitchen' AND price < 200
ORDER BY price;Both conditions must be TRUE for a row to stay.
SELECT order_id, status, quantity
FROM orders
WHERE (status = 'shipped' OR status = 'processing')
AND quantity >= 2
ORDER BY order_id;Without the parentheses, quantity >= 2 would apply only to processing orders.
SELECT order_id, ordered_at, status
FROM orders
WHERE ordered_at >= '2025-03-01' AND ordered_at < '2025-04-01'
ORDER BY ordered_at
LIMIT 10;A half-open range (>= start, < next start) captures the whole of March, including 31 March 23:59.
Pitfalls
Writing col = NULL instead of col IS NULL (it matches nothing).
Forgetting parentheses when mixing AND and OR.
Filtering a timestamp with BETWEEN '2025-03-01' AND '2025-03-31': it stops at 31 March 00:00:00 and misses the rest of that day.
Using a select-list alias in WHERE (column "alias" does not exist): repeat the expression or wrap the query in a subquery/CTE.
Putting an aggregate in WHERE (aggregate functions are not allowed in WHERE): filter groups with HAVING.