Filters restrict rows returned by a ClickHouse query using clauses like WHERE, PREWHERE, HAVING, and FILTER.
WHERE removes rows that do not satisfy a boolean expression before data reaches the processing pipeline. Filtering early reduces memory, CPU, and network usage, giving faster queries and lower costs.
Start with SELECT columns FROM table WHERE condition
. Combine conditions with AND, OR, and parentheses. Use functions such as like()
, in()
, between
, and direct comparisons for numeric or date ranges.
Use PREWHERE when the condition targets fields in primary or data-skipping indexes that are highly selective. ClickHouse reads only matching granules, reducing disk I/O before evaluating complex expressions.
SELECT id, order_date, total_amount
FROM Orders
PREWHERE order_date >= '2024-01-01'
WHERE total_amount > 100;
Apply HAVING after GROUP BY to keep groups that meet a condition, or use a subquery and filter its result for maximum flexibility.
SELECT customer_id, sum(total_amount) AS lifetime_value
FROM Orders
GROUP BY customer_id
HAVING lifetime_value > 1000;
Yes. Add FILTER (WHERE ...)
inside aggregate functions to include rows conditionally without CASE statements.
SELECT
count(*) FILTER (WHERE status = 'completed') AS completed_orders,
count(*) FILTER (WHERE status = 'cancelled') AS cancelled_orders
FROM Orders;
Keep filters sargable, avoid wrapping indexed columns in functions, use materialized columns for expensive expressions, build data-skipping indexes on frequently filtered fields, and pair PREWHERE with LIMIT to push work down early.
Use PREWHERE for highly selective conditions on indexed columns to reduce disk reads, then keep less selective or complex expressions in WHERE.
Yes. Place conditions after GROUP BY using HAVING or filter in an outer query. HAVING evaluates on aggregate values.
Absolutely. Append FILTER (WHERE ...)
inside aggregates to count or sum a subset of rows in the same SELECT list.