Grouping & aggregation

Unpivot columns into rows

3 min · updated June 16, 2026

Unpivot is the reverse of pivot: many columns become (key, value) rows. The portable form is UNION ALL, one branch per column — works in every dialect:

SELECT product, 'Q1' AS quarter, q1 AS amount FROM sales
UNION ALL SELECT product, 'Q2', q2 FROM sales
UNION ALL SELECT product, 'Q3', q3 FROM sales
UNION ALL SELECT product, 'Q4', q4 FROM sales;

A tidier version that reads the table once (PostgreSQL, DuckDB, and any engine with LATERAL):

-- PostgreSQL / DuckDB
SELECT s.product, v.quarter, v.amount
FROM sales s
CROSS JOIN LATERAL (VALUES
  ('Q1', s.q1), ('Q2', s.q2), ('Q3', s.q3), ('Q4', s.q4)
) AS v(quarter, amount);

BigQuery, Snowflake and DuckDB have a dedicated UNPIVOT operator:

-- BigQuery / Snowflake / DuckDB
SELECT product, quarter, amount
FROM sales
UNPIVOT (amount FOR quarter IN (q1, q2, q3, q4));

NULL handling. UNION ALL keeps rows where the value is NULL; the UNPIVOT operator excludes them by default (add INCLUDE NULLS to keep them). Pick the behaviour you want, especially when some quarters are empty.

← All recipes