Aggregates With FILTER (Conditional Aggregation)
Count completed vs cancelled orders in one pass using FILTER clauses.
Overview
DuckDB (and Postgres) support a FILTER (WHERE …) clause on aggregates, letting
you compute conditional aggregates in a single GROUP BY query — no CASE
required. Here we count completed and cancelled orders per product category side
by side.
The Query
Store (Customers/Orders/Products)
Loading database engine...
Step-by-Step Breakdown
COUNT(*) FILTER (WHERE o.status = 'completed')— counts only completed orders in each category.COUNT(*) FILTER (WHERE o.status = 'cancelled')— counts only cancelled ones.- Both share the same
GROUP BY p.category, so they align per category.
FILTER vs CASE
COUNT(*) FILTER (WHERE …) is equivalent to COUNT(CASE WHEN … THEN 1 END)
but reads more cleanly and is often faster.
Variations
Average salary of active vs all employees per department:
Employees & Departments
Loading database engine...
Common Mistakes
- Using FILTER where unsupported. MySQL lacks
FILTER; fall back toCASE. Know your engine. - Forgetting the aggregate.
FILTERmodifies an aggregate; you can't writecol FILTER (WHERE …)on a bare column. - Doubling counts.
COUNT(*) FILTERstill respects theGROUP BY; don't also add aWHERE status = …that drops the other rows you wanted to count.