Reshaping Rows and Columns with PIVOT and UNPIVOT in SQL
PIVOT turns row values into columns for a crosstab; UNPIVOT flips those columns back into rows.
In
Lesson 16.1 · Pivoting with conditional aggregation
you built a crosstab by hand with
count(*) filter (where ...). DuckDB also has a dedicated
PIVOT
statement that turns the values in one column into headers automatically. No
need to name each status yourself.
The shape is
PIVOT source ON header_column USING aggregate GROUP BY kept_rows. Its opposite,
UNPIVOT, folds several columns back into name/value rows, which is handy for
tidying a wide spreadsheet into long form.
-- wide: each status value becomes a column
create or replace temp table status_by_customer as
pivot orders on status using count(*) group by customer_id;
-- long again: those columns fold back into name/value rows
unpivot status_by_customer
on cancelled, pending, processing, shipped
into name status value orders; A DuckDB convenience
PIVOT
and
UNPIVOT
as standalone statements are DuckDB's own syntax. SQL Server, Oracle,
Snowflake, and BigQuery have PIVOT and UNPIVOT
too, but as operators inside FROM, each spelled a little
differently, and PostgreSQL and MySQL have neither. The portable alternative
is conditional aggregation with CASE expressions, as in Lesson
16.1.
Schema · Garden Shop Table · orders 6 columns · 24 rows
One row per order. Unshipped orders have a null shipped_date.
Build a crosstab of order counts by month and status: one row per month and one column per status (cancelled, pending, processing, shipped). Start from the long-form starter query and pivot it.
Run your query to inspect the result.
Expected answer
- One row per month (six rows), one column per status value.
- Columns: month, cancelled, pending, processing, shipped.
- Months with no orders of a status show 0 in that cell.
That's the last lesson in “Summary Reports and Pivots.”
The next chapter builds on what this one covered.
Start Chapter 17: Guided Playground Missions → Begins with 17.1 Map a dataset before queryingRelated
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.