Microsoft Power BI • Data Preparation with Power Query

Pivot/Unpivot

Reshape tabular data between wide and long formats to unlock flexible analysis in Power Query.

Microsoft Power BI emblem with a dashboard, stacked chart, and database.
Inside this lesson 10 sections 5 questions 8 figures

SECTION 1

Historical Context & Motivation

The challenge of reshaping tabular data between different structural representations is as old as relational databases themselves. When E. F. Codd formalized the relational model in 1970, he established that data should be stored in normalized, flat tables with minimal redundancy. However, analysts and decision-makers often needed the same data presented in cross-tabulated summaries—what we now call pivot tables. This tension between normalized storage and denormalized presentation has driven decades of innovation in data transformation tooling, culminating in the pivot and unpivot operations available in modern ETL engines like Power Query.

1970 • Codd's Relational Model

E. F. Codd publishes "A Relational Model of Data for Large Shared Data Banks," establishing the theoretical foundation for normalized data storage in rows and columns.

1993 • Excel PivotTables

Microsoft Excel 5.0 introduces PivotTables, allowing business users to cross-tabulate row-level data into summary matrices interactively—popularizing the 'pivot' concept far beyond the database community.

2005 • SQL PIVOT / UNPIVOT

Microsoft SQL Server 2005 adds the PIVOT and UNPIVOT relational operators to T-SQL, formalizing in-database reshaping of result sets without application-layer code.

2013 • Power Query for Excel

Microsoft releases Power Query as an Excel add-in, exposing a GUI-driven Pivot Columns and Unpivot Columns transformation backed by the M language, making reshape operations accessible to non-programmers.

2015–Present • Power BI Desktop

Power BI Desktop ships with Power Query Editor fully integrated, establishing pivot and unpivot as first-class data preparation steps in the modern self-service BI workflow.

The fundamental question these operations address is straightforward yet critical: how do you transform a dataset from a wide format (many columns, few rows) into a long format (few columns, many rows), or vice versa, without losing information? Understanding pivot and unpivot operations is essential for anyone who needs to wrangle real-world data—data that rarely arrives in the exact shape a model or visualization requires.

SECTION 2

Core Principles & Definitions

At their core, pivot and unpivot are inverse reshaping operations that redistribute data between the row and column dimensions of a table. Neither operation adds nor removes data; they simply restructure the geometry of the table to suit different analytical contexts. Before examining the mechanics, it helps to establish the foundational ideas that govern these transformations.

1

Pivot (Wide Format)

Pivoting rotates distinct values from a single attribute column into multiple new columns, aggregating the associated measure values. The result is a wider table with fewer rows—ideal for cross-tabulated summaries and matrix-style reports.
2

Unpivot (Long Format)

Unpivoting collapses multiple columns back into two columns: an attribute column holding the former column names and a value column holding the corresponding cell values. This normalizes the table into a long, narrow shape preferred by most data models.
3

Attribute–Value Pairs

Every unpivot operation generates attribute–value pairs (also called name–value or key–value pairs). This entity-attribute-value (EAV) pattern is the structural backbone of the long format and directly maps to tidy data principles.
4

Anchor Columns

When unpivoting, certain columns remain fixed—these 'anchor' or 'identifier' columns are not unpivoted. They repeat across every generated row, maintaining the relational context for each attribute–value pair.
5

Aggregation in Pivot

When pivoting, if multiple source rows map to the same cell in the result, an aggregation function (sum, count, average, etc.) must be applied. Power Query defaults to 'Don't Aggregate' but offers several built-in options.
✦

KEY TAKEAWAY

Think of pivot and unpivot as transposing a matrix in linear algebra—except instead of a simple dimension swap, you are also managing labels and potential aggregation. Pivoting is like converting a normalized relational table into a spreadsheet-style cross-tab; unpivoting reverses that transformation, recovering the normalized form. Just as a matrix and its transpose encode the same information in different orientations, pivot and unpivot preserve data while changing the table's shape to fit different downstream consumers.

SECTION 3

Visual Explanation — Pivot vs. Unpivot

Pivot & Unpivot: Data ReshapingLONG FORMAT (Normalized)ProductQuarterSalesWidgetQ1100WidgetQ2150WidgetQ3200GadgetQ180GadgetQ290GadgetQ3120WIDE FORMAT (Cross-tab)ProductQ1Q2Q3Widget100150200Gadget8090120PIVOTUNPIVOTConceptual MappingAnchor ColumnAttribute ColumnValue ColumnProductQuarterSalesStays fixedColumn names becomerow values (unpivot)Cell values collectedinto single columnRow values become column headers (pivot)
The diagram illustrates how a long-format table with three columns (Product, Quarter, Sales) is pivoted into a wide-format cross-tab where each quarter becomes its own column. The reverse arrow shows the unpivot path. The bottom section highlights the three column roles: anchor, attribute, and value.

The visual above captures the essential geometry of both operations. In the long-format table on the left, the Quarter column contains repeated categorical values (Q1, Q2, Q3) while the Sales column holds the corresponding numeric measures. When we pivot on the Quarter column, each distinct value becomes a new column header in the wide-format table on the right, and the Sales values fill the cells at the intersection of each Product and Quarter. Conversely, unpivoting the wide table collapses Q1, Q2, and Q3 back into a single attribute column, regenerating the original six rows. Note how the Product column acts as the anchor in both directions—it is the invariant identifier that ties each attribute–value pair to its entity.

SECTION 4

How Pivot & Unpivot Work Under the Hood

While Power Query provides a graphical interface for these operations, it is instructive to understand the underlying M language (informally called Power Query Formula Language) functions that execute the transformations. Each GUI click in Power Query Editor generates an M step in the Applied Steps pane. Grasping these functions allows you to customize behavior, handle edge cases, and debug unexpected results.

Pivot: Table.Pivot

The M function Table.Pivot(table, pivotValues, attributeColumn, valueColumn, aggregationFunction) accepts five arguments. The pivotValues parameter is a list of the distinct values that will become new column headers. The attributeColumn names the column whose values are being rotated into headers, while the valueColumn names the column whose values will populate the new cells. The optional aggregationFunction specifies how to resolve collisions when multiple source rows map to the same destination cell—for instance, List.Sum or List.Average.

PIVOT M FUNCTION SIGNATURE

Table.Pivot(table,pivotValues,attributeColumn,valueColumn,aggregationFunction)Table.Pivot(table, pivotValues, attributeColumn, valueColumn, aggregationFunction)

table = source table; pivotValues = list of distinct attribute values (e.g., {"Q1","Q2","Q3"}); attributeColumn = column to rotate; valueColumn = column supplying cell data; aggregationFunction = collision resolver (optional).

Unpivot: Table.UnpivotOtherColumns

Power Query offers three unpivot variants. Table.Unpivot unpivots a specified list of columns. Table.UnpivotOtherColumns is the preferred approach because it specifies which columns to keep (the anchors), automatically unpivoting everything else. This is resilient to schema changes—if new quarter columns appear in the source, they are automatically included. Finally, Table.UnpivotColumns ("Unpivot Only Selected Columns") targets an explicit list and ignores additions.

UNPIVOT M FUNCTION SIGNATURE

Table.UnpivotOtherColumns(table,pivotColumns,attributeColumnName,valueColumnName)Table.UnpivotOtherColumns(table, pivotColumns, attributeColumnName, valueColumnName)

table = source table; pivotColumns = list of columns to keep as anchors (e.g., {"Product"}); attributeColumnName = name for the generated attribute column (e.g., "Quarter"); valueColumnName = name for the generated value column (e.g., "Sales").

Row Count Relationships

A useful mental model involves the row-count identities. If a long table has R rows, K distinct anchor-group keys, and D distinct attribute values, then after pivoting, the wide table has K rows and D new columns (plus the anchor columns). In the fully balanced case (no missing combinations), R = K × D. After unpivoting the wide table, you recover R rows. If the wide table contains null cells—meaning some combinations are absent—unpivoting produces fewer rows than K × D unless you explicitly keep null rows.

ROW-COUNT IDENTITY (BALANCED CASE)

Rlong=K×D;Rwide=K;Columnswide=D+∣anchorcolumns∣R_long = K × D ; R_wide = K ; Columns_wide = D + |anchor columns|

R_long = row count of the long table; K = number of distinct entity groups; D = number of distinct attribute values; |anchor columns| = number of identifier columns that are not pivoted.

SECTION 5

Unpivot Variants & Best Practices

Power Query's three unpivot modes differ primarily in how they respond to schema evolution—new columns appearing or disappearing in the upstream data source. Choosing the right variant is a design decision with maintenance implications, analogous to choosing between implicit and explicit column selection in a SQL SELECT statement. The following diagram and table break down the variants and their trade-offs.

Three Unpivot Variants in Power QueryUnpivot ColumnsTable.UnpivotYou specify which columnsto unpivot by name.Explicit listNew columns ignoredUnpivot Other ColumnsTable.UnpivotOtherColumnsYou specify which columnsto KEEP as anchors.Anchor list✓ RecommendedUnpivot Only SelectedTable.UnpivotColumnsSame as Unpivot Columnsbut menu-driven selection.Explicit listNew columns ignoredSchema Evolution BehaviorScenarioUnpivot ColumnsUnpivot OtherOnly SelectedSource adds "Q4" column✗ Ignored✓ Auto-included✗ IgnoredSource removes "Q3"✗ Error✓ Graceful✗ ErrorColumn order changes✓ OK (by name)✓ OK (by name)✓ OK (by name)Anchor column renamed✓ OK✗ Error✓ OK
The three cards compare the M function signatures and column-specification strategies. The table below summarizes how each variant handles four common schema-change scenarios. Table.UnpivotOtherColumns is generally the safest choice for production queries because it adapts automatically when new data columns appear.
💡

BEST PRACTICE

Default to Unpivot Other Columns when building production Power Query pipelines. Because it locks the anchor columns rather than the unpivoted columns, it naturally accommodates new data arriving in additional columns—such as a new fiscal quarter or a new product metric—without requiring manual query edits.

Handling Nulls During Unpivot

By default, Power Query's unpivot operations drop rows where the value is null. In many analytical scenarios this is desirable because it removes meaningless combinations. However, if null values carry semantic weight—for instance, a missing measurement that should be distinguished from a zero—you may need to replace nulls with a sentinel value before unpivoting, then restore them afterward. This can be accomplished using Table.ReplaceValue in a preceding step.

SECTION 6

Worked Example — Unpivoting Monthly Sales Data

Suppose you receive a CSV export from a legacy accounting system. The file has one row per product and separate columns for each month's revenue: Product, Jan, Feb, Mar, Apr. Your Power BI data model requires a star schema with a single Revenue fact column and a Month column that can be related to a Date dimension. Let's walk through the unpivot process step by step.

ProductJanFebMarApr
Alpha1200135011001500
Beta800null950870
Gamma2000210019502200

Source data — wide format with monthly revenue columns

Unpivoting Monthly Columns in Power Query

  1. 1

    Step 1 — Load Data into Power Query

    In Power BI Desktop, select Get Data → Text/CSV and load the file. Power Query Editor opens with the table displayed above. Note that Jan through Apr are separate columns—this is the wide format.
  2. 2

    Step 2 — Select Anchor Columns

    Click on the Product column header to select it. This is the identifier column that should remain fixed. All other columns (Jan, Feb, Mar, Apr) are the ones we want to unpivot.
  3. 3

    Step 3 — Apply Unpivot Other Columns

    With Product selected, navigate to Transform → Unpivot Columns → Unpivot Other Columns. Power Query generates the M step: Table.UnpivotOtherColumns(PreviousStep, {"Product"}, "Attribute", "Value"). The result is a three-column table.
    11 rows generated (3 products × 4 months − 1 null dropped).
  4. 4

    Step 4 — Rename Generated Columns

    Double-click the "Attribute" column header and rename it to Month. Rename "Value" to Revenue. These descriptive names improve downstream DAX readability.
  5. 5

    Step 5 — Set Data Types

    Change the type of Revenue to Whole Number (or Decimal Number as appropriate) and Month to Text. Click Close & Apply. The long-format table is now ready for the data model.
    Final table: Product (text), Month (text), Revenue (whole number) — 11 rows.

Notice that the row for Beta / Feb was automatically dropped because the source cell was null. If retaining that row is important, insert a Table.ReplaceValue(Source, null, 0, Replacer.ReplaceValue, {"Jan","Feb","Mar","Apr"}) step before the unpivot to substitute nulls with zero (or another sentinel).

SECTION 7

Pivot vs. Unpivot — Strengths & Limitations

DimensionPivot (Wide)Unpivot (Long)
ReadabilityFamiliar cross-tab layout; easy for human scanning of matrix data.Many rows, harder to scan visually; requires filtering or grouping for summaries.
Data Model FitViolates tidy data / 3NF; column names encode data values.Aligns with star schema, tidy data principles; each variable has its own column.
Schema StabilityNew categories require new columns—report and DAX expressions must be updated.New categories appear as new rows; no schema change required.
AggregationRequires an aggregation function when multiple source rows map to one cell.No aggregation needed; each row is an atomic observation.
DAX / Measure AuthoringHarder—measures must reference specific column names, complicating dynamic analysis.Easier—CALCULATE with filters on the attribute column enables flexible measures.
Use CasesFinal-stage formatting for matrix visuals, export to Excel, or dashboard cards.Standard shape for fact tables, time-series analysis, and relational joins.

Comparative analysis of Pivot (wide) vs. Unpivot (long) formats

✦

KEY TAKEAWAY

In a well-architected Power BI solution, the data model's fact tables should nearly always be in long (unpivoted) format because DAX measures and the VertiPaq engine are optimized for tall, narrow tables with high-cardinality row counts. Pivoting is best reserved for the presentation layer—think of it as the 'last mile' formatting before a report visual, not a structural choice for your model.

SECTION 8

Connection to Advanced Theory & Tools

The pivot and unpivot pattern extends far beyond Power Query and connects to fundamental concepts in data engineering and computer science. In relational algebra, pivoting corresponds to a combination of grouping, aggregation, and conditional projection, while unpivoting maps to a cross-join of the anchor set with the attribute domain, followed by a selective projection. Understanding these algebraic roots deepens your ability to reason about correctness and performance.

ConceptPower Query (Beginner)Advanced / Cross-Platform
UnpivotTable.UnpivotOtherColumns in M languagepandas.melt() in Python; tidyr::pivot_longer() in R; UNPIVOT in T-SQL and Spark SQL
PivotTable.Pivot with optional aggregationpandas.pivot_table() in Python; tidyr::pivot_wider() in R; PIVOT in T-SQL; .groupBy().pivot() in Spark
Tidy DataAchieved via unpivot; each variable in its own columnHadley Wickham's tidy data principles (2014); third normal form in relational theory
Dynamic PivotingLimited—pivot values are typically hard-coded in the M stepDynamic SQL with STUFF/STRING_AGG; parameterized M queries; dbt macros for dynamic column generation
EAV PatternProduced naturally by unpivot (Attribute + Value columns)Entity-Attribute-Value schema design in healthcare (HL7), IoT telemetry, and metadata-driven architectures

Mapping Power Query concepts to advanced and cross-platform equivalents

As you move into enterprise-scale data engineering with tools like Apache Spark, dbt, or cloud data warehouses, you will encounter the same reshape primitives under different function names. The conceptual fluency you build with Power Query's pivot and unpivot transfers directly, because the underlying mathematical operation—redistributing data between row and column dimensions—is universal.

SECTION 9

Practice Problems

Question 1: CONCEPTUAL

A colleague argues that pivoting and unpivoting are purely cosmetic operations that don't affect the underlying data model. Explain why this claim is misleading, particularly in the context of Power BI's VertiPaq storage engine and DAX measure authoring.
Show answer
While it is true that pivot and unpivot do not add or remove data, they profoundly affect the data model's structure. A wide (pivoted) fact table forces DAX measures to reference specific column names—meaning a new category (e.g., a new quarter) requires modifying measures and potentially visuals. In contrast, a long (unpivoted) table stores categories as row values, allowing a single CALCULATE expression with a filter on the attribute column to handle any category dynamically. Furthermore, VertiPaq's columnar compression is more efficient on tall, narrow tables with low-cardinality columns than on wide tables where each column holds a heterogeneous mix of values. Therefore, the choice of shape has real implications for query performance, model maintainability, and report scalability.

Question 2: BASIC CALCULATION

A wide-format table has 50 product rows and 12 monthly columns (Jan through Dec) plus a Product column. How many rows will the unpivoted table have, assuming no null values exist in any monthly column?
Show answer
Using the row-count identity R_long = K × D, where K = 50 (distinct anchor groups, i.e., products) and D = 12 (distinct attribute values, i.e., months), we get R_long = 50 × 12 = 600 rows. The resulting table will have three columns: Product, Month (the attribute column holding 'Jan' through 'Dec'), and Value (the measure column). With no null values, every combination produces a valid row, so the full 600 rows are generated.

Question 3: INTERMEDIATE

You have a long-format table with columns Region, Metric, and Value. The Metric column contains values 'Revenue', 'Cost', and 'Profit'. You need to pivot this table so that each metric becomes its own column. However, some (Region, Metric) combinations have duplicate rows due to a data-entry error. Write the M expression for a pivot that sums the duplicates, and explain what would happen if you used the 'Don't Aggregate' option instead.
Show answer
The M expression would be: Table.Pivot(Source, {"Revenue", "Cost", "Profit"}, "Metric", "Value", List.Sum). The List.Sum aggregation function resolves collisions by summing all values that map to the same (Region, Metric) cell. If you used the 'Don't Aggregate' option (which passes null as the aggregation function, effectively using List.First or raising an error depending on the version), Power Query would either silently take the first matching value—discarding duplicates without warning—or throw an Expression.Error indicating that the pivot operation found multiple values for a single cell. In a production pipeline, neither silent data loss nor runtime errors is acceptable, so specifying an explicit aggregation like List.Sum, List.Average, or List.Count is the correct approach whenever duplicates are possible.

Question 4: APPLIED

An IoT sensor system exports a CSV file every day with columns: SensorID, Temperature, Humidity, Pressure. Your Power BI data model requires a single Measurement fact table with columns SensorID, MetricName, and MetricValue so that you can use a slicer to let users choose which metric to visualize. Describe the complete Power Query transformation pipeline, including the specific M functions and any additional steps for data typing and null handling.
Show answer
First, load the CSV using Csv.Document and promote headers with Table.PromoteHeaders. Next, set the data types for Temperature, Humidity, and Pressure to type number, and SensorID to type text, using Table.TransformColumnTypes. If null values should be preserved (e.g., a sensor offline), insert Table.ReplaceValue(PreviousStep, null, -999, Replacer.ReplaceValue, {"Temperature","Humidity","Pressure"}) to substitute a sentinel. Then apply Table.UnpivotOtherColumns(PreviousStep, {"SensorID"}, "MetricName", "MetricValue"). Rename columns if needed with Table.RenameColumns. If sentinels were inserted, use Table.ReplaceValue to convert -999 back to null. Finally, set MetricValue to type number and MetricName to type text. This pipeline produces a normalized fact table that can be related to a Sensor dimension and filtered dynamically in reports via a MetricName slicer.

Question 5: CRITICAL THINKING

Consider the scenario where a source system adds new metric columns quarterly (e.g., a 'CustomerSatisfaction' column appears in Q2). Compare and contrast the maintenance burden of (a) using Table.Unpivot with an explicit column list versus (b) using Table.UnpivotOtherColumns with an explicit anchor list. Then propose a hybrid M strategy that auto-detects new columns but also validates that only expected data types are unpivoted, raising an alert if an unexpected text column appears among numeric metrics.
Show answer
With Table.Unpivot({"Temperature","Humidity","Pressure"}, ...), the new CustomerSatisfaction column is silently ignored—the report shows no error but misses data, which is a subtle and dangerous failure mode. With Table.UnpivotOtherColumns({"SensorID"}, ...), the new column is automatically included, which is ideal if it is a valid numeric metric. However, if someone adds a non-numeric column (e.g., a Notes text field), it would be unpivoted into MetricValue, causing type errors or polluting the fact table. A hybrid strategy uses Table.UnpivotOtherColumns for resilience, then adds a validation step: let expectedTypes = {"Temperature", type number}, {"Humidity", type number}, etc., and use Table.Schema or Table.ColumnNames to detect columns not in the expected list. For each new column, check its type with Value.Type; if it matches type number, allow it through; otherwise, raise an error with error Error.Record("Schema Validation", "Unexpected non-numeric column detected: " & colName). This approach combines the automatic inclusion benefit of UnpivotOtherColumns with a type-safety guard, balancing flexibility and reliability in a production ETL pipeline.

SUMMARY

Lesson Summary

Summary

The pivot operation transforms a long-format table into a wide-format cross-tab by rotating distinct attribute values into column headers and filling cells with measure values, optionally applying an aggregation function to resolve duplicate mappings. The inverse unpivot operation collapses multiple columns into attribute–value pairs, producing the normalized shape preferred by Power BI's VertiPaq engine and DAX measure authoring.

Power Query exposes these operations through the M functions Table.Pivot and Table.UnpivotOtherColumns, with the latter being the recommended variant for production pipelines due to its resilience to schema evolution. The row-count identity R = K × D provides a quick sanity check on transformation correctness. These reshape primitives—universal across SQL, Python pandas, R tidyr, and Spark—are foundational skills for any data professional building reliable, maintainable analytical models.

Varsity Tutors • Microsoft Power BI • Pivot/Unpivot