Convert Rows to columns using 'Pivot' in SQL Server
Transforming Data: Converting Rows to Columns with SQL Server PIVOT

Learn how to reshape your data from a row-based format to a column-based format using the powerful PIVOT operator in SQL Server. This guide covers basic and dynamic pivoting techniques.
Data often comes in various shapes, and sometimes, the default row-oriented structure isn't ideal for analysis or reporting. SQL Server's PIVOT
operator provides an elegant solution to transform unique values from one column into multiple new columns, aggregating other column values in the process. This technique is invaluable for creating summary reports, cross-tabulations, and making data more readable for specific use cases.
Understanding the PIVOT Operator
The PIVOT
operator rotates a table-valued expression by turning the unique values from one column into multiple columns and performing aggregations on the remaining column values that are desired in the output. It's a powerful tool for data transformation, but it requires a clear understanding of its components: the PIVOT
clause itself, the aggregation function, and the column to be pivoted.
flowchart TD A[Original Data] --> B{"Select Columns for Pivot"} B --> C["Specify Pivot Column (e.g., Category)"] C --> D["Define Aggregation (e.g., SUM, COUNT)"] D --> E["List Pivot Values (e.g., 'Sales', 'Marketing')"] E --> F[PIVOT Operator] F --> G[Resulting Pivoted Data] G --> H["Further Analysis/Reporting"]
Conceptual flow of the PIVOT operation in SQL Server.
Basic PIVOT Syntax and Example
Let's start with a simple scenario. Imagine you have sales data with product categories and sales amounts, and you want to see the total sales for each category as a separate column. The basic PIVOT
syntax requires you to explicitly list the values you want to turn into columns. This is known as static pivoting.
CREATE TABLE SalesData (
SaleID INT PRIMARY KEY,
ProductCategory VARCHAR(50),
SaleAmount DECIMAL(10, 2)
);
INSERT INTO SalesData (SaleID, ProductCategory, SaleAmount) VALUES
(1, 'Electronics', 150.00),
(2, 'Books', 50.00),
(3, 'Electronics', 200.00),
(4, 'Clothing', 75.00),
(5, 'Books', 120.00),
(6, 'Electronics', 300.00);
SELECT * FROM SalesData;
-- Basic PIVOT example
SELECT ProductCategory, Electronics, Books, Clothing
FROM (
SELECT ProductCategory, SaleAmount
FROM SalesData
) AS SourceTable
PIVOT
(
SUM(SaleAmount)
FOR ProductCategory IN ([Electronics], [Books], [Clothing])
) AS PivotTable;
Setting up sample data and performing a basic static PIVOT.
PIVOT
, ensure the column names in the IN
clause exactly match the unique values from the column you are pivoting. Also, remember to enclose column names with special characters or spaces in square brackets []
.Dynamic PIVOT for Unknown Column Values
The static PIVOT
works well when you know all the values you want to pivot into columns beforehand. However, in many real-world scenarios, these values might change or be unknown. This is where dynamic PIVOT
comes into play, typically implemented using dynamic SQL. This approach constructs the PIVOT
query string at runtime based on the distinct values present in your data.
DECLARE @ColumnList VARCHAR(MAX);
DECLARE @PivotQuery NVARCHAR(MAX);
-- Get distinct product categories for dynamic columns
SELECT @ColumnList = STUFF((
SELECT DISTINCT ',' + QUOTENAME(ProductCategory)
FROM SalesData
FOR XML PATH('')
), 1, 1, '');
-- Construct the dynamic PIVOT query
SET @PivotQuery =
'SELECT ' + @ColumnList + '
FROM (
SELECT ProductCategory, SaleAmount
FROM SalesData
) AS SourceTable
PIVOT
(
SUM(SaleAmount)
FOR ProductCategory IN (' + @ColumnList + ')
) AS PivotTable;';
-- Execute the dynamic query
EXEC sp_executesql @PivotQuery;
Implementing a dynamic PIVOT using SQL Server's STUFF
and FOR XML PATH
.
QUOTENAME()
helps prevent issues with column names.Common Pitfalls and Best Practices
While PIVOT
is a powerful feature, there are a few things to keep in mind to avoid common issues and ensure optimal performance:
- Aggregation Function: You must specify an aggregation function (e.g.,
SUM
,COUNT
,AVG
,MIN
,MAX
) within thePIVOT
clause. If multiple rows contribute to a single pivoted cell, this function determines the final value. - NULL Values: If a pivoted column has no corresponding data for a particular row,
PIVOT
will returnNULL
for that cell. You can useISNULL()
orCOALESCE()
to replace theseNULL
s with zeros or other default values if needed. - Performance: For very large datasets or highly dynamic pivots, consider if
PIVOT
is the most performant solution. Sometimes, conditional aggregation usingCASE
statements might offer better performance or more flexibility, especially if you only need to pivot a few columns. - Column Aliases: Always alias your pivoted columns for clarity, especially in dynamic pivots where the generated column names might be less descriptive.
-- Example of handling NULLs with ISNULL
SELECT ISNULL(Electronics, 0) AS ElectronicsSales,
ISNULL(Books, 0) AS BooksSales,
ISNULL(Clothing, 0) AS ClothingSales
FROM (
SELECT ProductCategory, SaleAmount
FROM SalesData
) AS SourceTable
PIVOT
(
SUM(SaleAmount)
FOR ProductCategory IN ([Electronics], [Books], [Clothing])
) AS PivotTable;
Using ISNULL
to replace NULL
values in pivoted columns.