SQL SERVER – UNPIVOT Table Example

My previous article SQL SERVER – PIVOT Table Example encouraged few of my readers to ask me question about UNPIVOT table. UNPIVOT table is reverse of PIVOT Table.

USE AdventureWorks
GO
CREATE TABLE #Pvt ([CA] INT NOT NULL,
[AZ] INT NOT NULL,
[TX] INT NOT NULL);
INSERT INTO #Pvt ([CA], [AZ], [TX])
SELECT [CA], [AZ], [TX] FROM
(
SELECT sp.StateProvinceCode
FROM Person.Address a
INNER JOIN Person.StateProvince sp
ON a.StateProvinceID = sp.StateProvinceID
) p
PIVOT
(
COUNT (StateProvinceCode)
FOR StateProvinceCode
IN ([CA], [AZ], [TX])
)
AS pvt;
SELECT StateProvinceCode, Customer_Count
FROM
(
SELECT [CA], [AZ], [TX] FROM #Pvt
) t
UNPIVOT
(
Customer_Count
FOR StateProvinceCode
IN ([CA], [AZ], [TX])
)
AS unpvt;
DROP TABLE #Pvt;
GO

SQL Server Unpivot Table.

What to Know Before You Use an UNPIVOT Table Query

UNPIVOT turns columns into rows. In the example, the three state columns CA, AZ and TX become three rows, each with a state code and a count. It is handy when data arrives in a wide shape, like a spreadsheet with one column per month, and you need it in a normal table with one row per value.

Keep these points in mind:

  • All columns in the IN list must have exactly the same data type, including the length. If one column is INT and another is BIGINT, or two varchar columns have different lengths, the query fails. Convert them to one type in the inner query first.
  • UNPIVOT quietly drops rows where the value is NULL. If a NULL means something in your data, replace it with ISNULL in the inner query, or use another method.
  • The names of the value column and the name column, Customer_Count and StateProvinceCode in the example, are new names you choose. They do not need to exist anywhere.

As I explained in the PIVOT post, UNPIVOT cannot bring back the detail rows once PIVOT has aggregated them. Here the counts come back as three numbers, not as the many addresses behind them. That is expected. Think of UNPIVOT as changing the shape of the data, not as undoing a calculation.

A quick way to check your work is to count. The number of rows UNPIVOT returns should equal the number of source rows times the number of columns in the IN list, minus the NULL values it dropped. If the numbers do not match, look at the NULL values first.

On SQL Server 2008 and later, CROSS APPLY with a VALUES list does the same job and gives you more control. It keeps NULL values, and it can turn several groups of columns into rows at once. I use UNPIVOT for simple cases and CROSS APPLY when the shape gets more complex.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.

PIVOT and UNPIVOT, SQL Function, SQL Scripts
Previous Post
SQL SERVER – SQL SERVER – UDF – Get the Day of the Week Function – Part 3
Next Post
SQL SERVER – Create Default Constraint Over Table Column

Related Posts

12 Comments. Leave new

  • this is the original data

    Loc_Id doctorName Qualification Dept
    ——- ————– ————- ——
    1 abc M.B.B.S. Op
    2 xyz D.H.M.S. DP
    3 ppt H.M. CP

    I want to convert it like bellow

    Loc1 Loc2 Loc3
    ——– ———- ——-
    abc xyz ppt
    M.B.B.S. D.H.M.S. H.M.
    OP DP CP

    please help me

    Reply
  • Brett Phipps
    April 6, 2011 2:20 am

    I’m a little confused about your example here. Why go to all this trouble when you could just write this and get the same results.

    Select sp.StateProvinceCode
    ,Count(*) as Customer_count
    From Person.Address a
    Inner join Person.StateProvince sp
    On a.StateProvinceID = sp.StateProvinceID
    Where sp.StateProvinceCode in (‘CA’, ‘AZ’, ‘TX’)
    Group by sp.StateProvinceCode

    Reply
  • Hi Pinal, this is of great use.

    But i do have 1 more query that if i have a temp table where rows can have any data and i need to pivot that.
    For example i have a output like

    Description Subject Marks
    FA1 Sub1 10
    FA1 Sub2 15
    FA1 Sub3 11
    FA1 Sub4 12
    FA2 Sub1 9
    FA2 Sub2 8
    FA2 Sub3 12
    FA2 Sub4 10

    I need output like

    Subject FA1 FA2
    Sub1 10 9
    Sub2 15 8
    Sub3 11 12
    Sub4 12 10

    Then how can i achieve this, as Description can be more then that

    Thanks
    Sumit Gupta

    Reply
    • GAURAV RASTOGI
      March 10, 2014 10:00 pm

      SELECT [SUBJECT] , FA1 , FA2 FROM FAPIVOT
      PIVOT (SUM(MARKS) FOR FAE IN (FA1 , FA2))
      AS TBLPIVOT

      ABOVE IS THE QUERY

      Reply
  • TABLE X (A,B,C) & TABLE Y(A,B,C)
    data: TABLE X(1,2,3) , TABLE Y(2,3,4)

    PIVOT looks like

    X Y
    ————
    A 1 2
    B 2 3
    C 3 4

    Reply
  • Hi required output in following format
    INPUT
    X Y
    1 1
    2 2
    3 3
    4 4

    OUTPUT
    X 1
    X 2
    X 3
    X 4
    Y 1
    Y 2
    Y 3
    Y 4

    Reply
  • Hi

    This is my store procedure. I need to store the value into table
    There is a error

    Msg 213, Level 16, State 1, Procedure usp_pivot_by_Date_Seats, Line 7
    Insert Error: Column name or number of supplied values does not match table definition.

    But Column and number of column are in order. Below is Store porcedure

    USE [SpectrumDB]
    GO
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[usp_pivot_by_Date_Seats]
    –@WeekNo Numeric
    AS
    BEGIN
    SET NOCOUNT ON;

    insert into tbl_Days_TEMP

    select * from ( select Title,Qty,WeekName from dbo.vw_RPT_Pivot_Weekly_Seat) DataTable
    PIVOT (SUM(Qty) FOR [weekname] IN ([Sunday],[Monday],[Tuesday],[Wednesday],[Thursday],
    [Friday],[Saturday])) PivotTable

    END

    Table tbl_Days_Temp is below

    USE [SpectrumDB]
    GO
    /****** Object: Table [dbo].[tbl_Days_TEMP] Script Date: 03/07/2013 21:49:22 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[tbl_Days_TEMP](
    [Title] [nvarchar](500) NULL,
    [WeekName] [nvarchar](50) NULL,
    [Value1] [numeric](18, 0) NULL CONSTRAINT [DF_tbl_Days_TEMP_Value1] DEFAULT ((0)),
    [Value2] [numeric](18, 0) NULL CONSTRAINT [DF_tbl_Days_TEMP_Value2] DEFAULT ((0)),
    [Value3] [numeric](18, 0) NULL CONSTRAINT [DF_tbl_Days_TEMP_Value3] DEFAULT ((0)),
    [Value4] [numeric](18, 0) NULL CONSTRAINT [DF_tbl_Days_TEMP_Value4] DEFAULT ((0)),
    [Value5] [numeric](18, 0) NULL CONSTRAINT [DF_tbl_Days_TEMP_Value5] DEFAULT ((0)),
    [Value6] [numeric](18, 0) NULL CONSTRAINT [DF_tbl_Days_TEMP_Value6] DEFAULT ((0)),
    [Value7] [numeric](18, 0) NULL CONSTRAINT [DF_tbl_Days_TEMP_Value7] DEFAULT ((0)),
    [Qty] [numeric](18, 0) NULL
    ) ON [PRIMARY]

    Pls help me where i did wrong

    Reply
  • Whats the point of putting an image instead of the code, just in case you want to test or play around?

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.