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 regionOn 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 ShopTable · products9 columns · 24 rows
One row per product, with price, cost, and inventory levels.
Build a per-category stock report. For each category returncategory_name, the total products, how many areavailable (not discontinued), how many arediscontinued, and the total on_hand quantity. Order by category name.
- Columns: category_name, products, available, discontinued, on_hand.
- Rows: one per category (8 rows).
- available + discontinued adds up to products within each row.
Related
Add subtotal and total rows to a grouped report.
Roll a group's values into one comma-separated cell.
Group on a CASE expression to bucket values.
Return several subtotal levels in one grouped query.