Pivot
Convert long-format data into wide format. Distinct values in the pivot column become new column headers; numeric values from another column are aggregated per row key. Use it to build summary cross-tabs, prepare data for spreadsheets, or invert an Unpivot earlier in the flow.
How it works
Section titled “How it works”Pivot is a full-dataset batch transform. It buffers the input, groups rows by the row-key columns, and promotes each distinct value of the pivot column into a new output column whose cell is an aggregate over the matching value column.
The output schema is data-dependent: column count grows with the number of distinct pivot values seen in the input. Empty cells (where a row-key/pivot-value combination has no source rows) are filled with 0 for sum and count aggregations and with "" for min, max, and avg.
When a single value spec is configured the new columns are named after the pivot value directly. With two or more value specs the column name takes the form {pivotValue}_{aggregation}_{valueColumn} to avoid collisions. The pivot column itself is dropped from the output (its values become headers); the value column is also dropped (its cells become aggregated cells).
If pivotColumns or values is empty, rows pass through unchanged.
Input: One tabular data connection. Output: A wide table with row-key columns, then one (or more) generated column per distinct pivot value.
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
pivotColumns | string[] | [] | Columns whose distinct values become new output columns. With multiple, values are joined with _ to form a composite header. |
rowKeys | string[] | [] | Columns that identify each output row. Cells with the same row-key combination collapse into one row. |
values | Array<{ column, aggregation }> | [] | Each entry names a numeric column and an aggregation: sum, count, avg, min, or max. Multiple entries produce multiple cells per pivot value. |
Examples
Section titled “Examples”Pivot quarterly sales by customer
Section titled “Pivot quarterly sales by customer”You have a long-format table of quarterly sales and want one row per customer with a column per quarter.
Before:
| customer | quarter | sales |
|---|---|---|
| Acme Corp | q1 | 1200 |
| Acme Corp | q2 | 1500 |
| Acme Corp | q3 | 1800 |
| Acme Corp | q4 | 2100 |
| Beta Inc | q1 | 800 |
| Beta Inc | q2 | 900 |
| Beta Inc | q3 | 1100 |
| Beta Inc | q4 | 1300 |
Configuration: pivot columns: ["quarter"], row keys: ["customer"], values: [{ column: "sales", aggregation: "sum" }].
After:
| customer | q1 | q2 | q3 | q4 |
|---|---|---|---|---|
| Acme Corp | 1200 | 1500 | 1800 | 2100 |
| Beta Inc | 800 | 900 | 1100 | 1300 |
Multiple aggregations produce composite column names
Section titled “Multiple aggregations produce composite column names”You want both total and order count per quarter so you can spot quarters with many small orders.
Before:
| customer | quarter | sales |
|---|---|---|
| Acme Corp | q1 | 600 |
| Acme Corp | q1 | 600 |
| Acme Corp | q2 | 1500 |
| Beta Inc | q1 | 800 |
| Beta Inc | q2 | 450 |
| Beta Inc | q2 | 450 |
Configuration: pivot columns: ["quarter"], row keys: ["customer"], values: [{ column: "sales", aggregation: "sum" }, { column: "sales", aggregation: "count" }].
After:
| customer | q1_sum_sales | q1_count_sales | q2_sum_sales | q2_count_sales |
|---|---|---|---|---|
| Acme Corp | 1200 | 2 | 1500 | 1 |
| Beta Inc | 800 | 1 | 900 | 2 |
Composite pivot columns
Section titled “Composite pivot columns”You want a cross-tab of region and channel as a single header.
Before:
| product | region | channel | revenue |
|---|---|---|---|
| Widget | EU | online | 500 |
| Widget | EU | retail | 300 |
| Widget | US | online | 800 |
| Gadget | EU | online | 200 |
| Gadget | US | retail | 400 |
Configuration: pivot columns: ["region", "channel"], row keys: ["product"], values: [{ column: "revenue", aggregation: "sum" }].
After:
| product | EU_online | EU_retail | US_online | US_retail |
|---|---|---|---|---|
| Widget | 500 | 300 | 800 | 0 |
| Gadget | 200 | 0 | 0 | 400 |
Tips and Edge Cases
Section titled “Tips and Edge Cases”- Default values for missing cells differ by aggregation. When a row-key/pivot-value pair has no source rows, the cell is filled with
0forsumandcount, and with""(empty string) formin,max, andavg. Be careful when chaining aChange Typetonumberdownstream — the""cells coerce tonull, not zero. Seeapps/web/src/transforms/pivot/logic.ts:72-75. - Pivot column order follows first-seen input order. The output columns appear in the order each distinct pivot value was first encountered while scanning the input rows. If you need alphabetical or numeric order (e.g.
q1, q2, q3, q4regardless of input shuffling), Sort Rows by the pivot column upstream. Seeapps/web/src/transforms/pivot/logic.ts:135-148. - A row key that also appears in
pivotColumnsorvaluesis silently dropped from the row-key set. The intersection guard atapps/web/src/transforms/pivot/logic.ts:125-127filters out collisions, so listing the same column in two slots is not an error — it is just ignored as a row key.