Skip to main content

When to use this

Sometimes your data is in the wrong shape for the analysis you need. Pivoting turns distinct row values into columns (e.g., turning monthly rows into one column per month). Unpivoting does the reverse — turning columns into rows (e.g., turning q1_revenue, q2_revenue, q3_revenue columns into quarter and revenue rows).

Sample input — Pivot

A monthly_sales table in the Raw layer, with one row per product per month:
productmonthrevenue
Widget AJanuary5000
Widget AFebruary7200
Widget AMarch6100
Widget BJanuary3200
Widget BFebruary4100
Widget BMarch3800
We want one row per product with a column for each month.

Sample input — Unpivot

A quarterly_revenue table where each quarter is a separate column:
productq1_revenueq2_revenueq3_revenue
Widget A183002210019500
Widget B111001320012800
We want to normalize this into product, quarter, and revenue columns.

Implementation — Pivot

BigQuery supports a native PIVOT clause for cleaner syntax.
SELECT *
FROM (
  SELECT product, month, revenue
  FROM `raw.monthly_sales`
)
PIVOT (
  SUM(revenue)
  FOR month IN ('January', 'February', 'March')
)
The values in the IN clause must be known at query time. If your months are dynamic, use the conditional aggregation approach shown in the Athena tab.

Pivot — Expected output

productJanuaryFebruaryMarch
Widget A500072006100
Widget B320041003800

Implementation — Unpivot

BigQuery supports a native UNPIVOT clause.
SELECT *
FROM `raw.quarterly_revenue`
UNPIVOT (
  revenue FOR quarter IN (
    q1_revenue AS 'Q1',
    q2_revenue AS 'Q2',
    q3_revenue AS 'Q3'
  )
)

Unpivot — Expected output

productquarterrevenue
Widget AQ118300
Widget AQ222100
Widget AQ319500
Widget BQ111100
Widget BQ213200
Widget BQ312800

Tips and gotchas

Pivoting requires knowing the distinct values upfront (months, quarters, etc.). If the values change over time, you’ll need to update the query. For fully dynamic pivots, the Python approach is the most flexible — you can read distinct values from the data and build the pivot programmatically.
After pivoting, column names come from data values and may contain spaces, special characters, or start with numbers. Clean them up with Rename columns if needed.