Pivoting with Conditional Aggregation in SQL
A pivot answers several sub-questions per group at once. Each becomes its own aggregate with a FILTER condition.
A plain
GROUP BY
gives you one number per group. A pivot gives you several:
one column for each condition, by putting a
FILTER
on each aggregate. It's how a single query becomes a small report.
count(*) filter (where …)
counts only the rows matching that condition, so you can count "available"
and "discontinued" side by side while still grouping once per category.
select region,
count(*) filter (where status = 'won') as won,
count(*) filter (where status = 'lost') as lost
from deals
group by region
On databases without
FILTER
(SQL Server, MySQL), the same idea is written as
sum(case when … then 1 else 0 end). DuckDB supports both;
FILTER
reads more cleanly.
Schema · Garden Shop Tables · products, categories 2 tables
One row per product, with price, cost, and inventory levels.
Lookup table of product categories.
Build a per-category stock report. For each category return
category_name, the total products, how many are
available (not discontinued), how many are
discontinued, and the total on_hand quantity.
Order by category name.
Run your query to inspect the result.
Expected answer
- Columns: category_name, products, available, discontinued, on_hand.
- Rows: one per category (8 rows).
- available + discontinued adds up to products within each row.
Related
COUNT, SUM, AVG, MIN, MAX, GROUP BY, and HAVING.
COUNT, SUM, AVG, GROUP BY, and HAVING.
Practice aggregate reports, HAVING, and answer shape.
Avoid truncating fractional results.
Filter groups with HAVING, rows with WHERE.
Searched and simple CASE patterns.