How to unpivot columns dynamically using SQL server 2014

  • Data in SQL table is

    Cust_NamePrd_Name1/1/20192/1/20193/1/2019
    JohnMobile18.545.766.9
    ScottLaptop9.53.70

    I want to unpivot columns [1/1/2019], [2/1/2019], [3/1/2019] and want the result as below

    Cust_NamePrd_NameSales_MonthValue
    JohnMobile1/1/201918.5
    JohnMobile2/1/201945.7
    JohnMobile3/1/201966.9
    ScottLaptop1/1/20199.5
    ScottLaptop2/1/20193.7
    ScottLaptop3/1/20190


    How can I do this? Also, the number of such columns which I want to unpivot is dynamic so it starts with 1/1/2019, 2/1/2019,....12/1/2019

  • Does this need to be dynamic? Are you adding new columns to your table each month (so next month you'll have a column 04/01/2019)? If so, I'd suggest that what you need to do isn't create a dynamic pivot, you need to fix your database design so that it's like the data in your second dataset. Or is that your aim of this? (But then like I said, there's no need for dynamic SQL.)

    Thom~

    Excuse my typos and sometimes awful grammar. My fingers work faster than my brain does.
    Larnu.uk

  • Thom A - Thursday, February 7, 2019 10:04 AM

    Does this need to be dynamic? Are you adding new columns to your table each month (so next month you'll have a column 04/01/2019)? If so, I'd suggest that what you need to do isn't create a dynamic pivot, you need to fix your database design so that it's like the data in your second dataset. Or is that your aim of this? (But then like I said, there's no need for dynamic SQL.)

    Yes, a new column will be added like 4/1/2019, 5/1/2019...
     And cannot change database design as this is how I get data, so I want to create SQL query (dynamic is one approach that I see) which will handle this and create data like the expected second dataset.

  • This is a way of doing it. It would be great if you could avoid this problem and get the unpivoted data to begin with, but that's something that might not be in your hands.

    CREATE TABLE SampleData(
      Cust_Name varchar(100),
      Prd_Name    varchar(100),
      [1/1/2019]    decimal(10, 4),
      [2/1/2019]    decimal(10, 4),
      [3/1/2019] decimal(10, 4)
    )
    INSERT INTO SampleData
    VALUES
      ('John', 'Mobile', 18.5,    45.7,    66.9),
      ('Scott', 'Laptop', 9.5,    3.7,    0);

    DECLARE @Columns NVARCHAR(MAX),
       @sql NVARCHAR(MAX);

    SELECT @Columns = STUFF(( SELECT CHAR(9) + ',( CAST( ' + QUOTENAME(name, '''') + ' AS date), ' + QUOTENAME(name) + ')' + CHAR(13)
    FROM sys.columns c
    WHERE object_id = OBJECT_ID('SampleData')
    AND c.name NOT LIKE '%[^0-9/]%'
        FOR XML PATH(''), TYPE).value('./text()[1]', 'nvarchar(max)'), 1, 2, '')
      

    SET @sql = N'SELECT Cust_Name, Prd_Name, SalesMonth, Value
    FROM SampleData
    CROSS APPLY (VALUES ' + @Columns + ')u( SalesMonth, Value)'

    PRINT @sql;
    EXEC(@SQL)
    GO
    DROP TABLE SampleData

    Luis C.
    General Disclaimer:
    Are you seriously taking the advice and code from someone from the internet without testing it? Do you at least understand it? Or can it easily kill your server?

    How to post data/code on a forum to get the best help: Option 1 / Option 2
  • Luis Cazares - Thursday, February 7, 2019 10:19 AM

    This is a way of doing it. It would be great if you could avoid this problem and get the unpivoted data to begin with, but that's something that might not be in your hands.

    CREATE TABLE SampleData(
      Cust_Name varchar(100),
      Prd_Name    varchar(100),
      [1/1/2019]    decimal(10, 4),
      [2/1/2019]    decimal(10, 4),
      [3/1/2019] decimal(10, 4)
    )
    INSERT INTO SampleData
    VALUES
      ('John', 'Mobile', 18.5,    45.7,    66.9),
      ('Scott', 'Laptop', 9.5,    3.7,    0);

    DECLARE @Columns NVARCHAR(MAX),
       @sql NVARCHAR(MAX);

    SELECT @Columns = STUFF(( SELECT CHAR(9) + ',( CAST( ' + QUOTENAME(name, '''') + ' AS date), ' + QUOTENAME(name) + ')' + CHAR(13)
    FROM sys.columns c
    WHERE object_id = OBJECT_ID('SampleData')
    AND c.name NOT LIKE '%[^0-9/]%'
        FOR XML PATH(''), TYPE).value('./text()[1]', 'nvarchar(max)'), 1, 2, '')
      

    SET @sql = N'SELECT Cust_Name, Prd_Name, SalesMonth, Value
    FROM SampleData
    CROSS APPLY (VALUES ' + @Columns + ')u( SalesMonth, Value)'

    PRINT @sql;
    EXEC(@SQL)
    GO
    DROP TABLE SampleData

    Thanks a lot, it worked. But I am new to SQL. Can you please help me to understand what exactly this 2 lines do

    STUFF(( SELECT CHAR(9) + ',( CAST( ' + QUOTENAME(name, '''') + ' AS date), ' + QUOTENAME(name) + ')' + CHAR(13)

    FOR XML PATH(''), TYPE).value('./text()[1]', 'nvarchar(max)'), 1, 2, '')

  • vikasjagadale8 - Thursday, February 7, 2019 2:43 PM

    Thanks a lot, it worked. But I am new to SQL. Can you please help me to understand what exactly this 2 lines do

    STUFF(( SELECT CHAR(9) + ',( CAST( ' + QUOTENAME(name, '''') + ' AS date), ' + QUOTENAME(name) + ')' + CHAR(13)

    FOR XML PATH(''), TYPE).value('./text()[1]', 'nvarchar(max)'), 1, 2, '')

    To fully understand the solution, please read the following articles:
    Creating a concatenated string using FOR XML

    Using CROSS APPLY VALUES to unpivot

    Luis C.
    General Disclaimer:
    Are you seriously taking the advice and code from someone from the internet without testing it? Do you at least understand it? Or can it easily kill your server?

    How to post data/code on a forum to get the best help: Option 1 / Option 2
  • Luis Cazares - Thursday, February 7, 2019 2:53 PM

    vikasjagadale8 - Thursday, February 7, 2019 2:43 PM

    Thanks a lot, it worked. But I am new to SQL. Can you please help me to understand what exactly this 2 lines do

    STUFF(( SELECT CHAR(9) + ',( CAST( ' + QUOTENAME(name, '''') + ' AS date), ' + QUOTENAME(name) + ')' + CHAR(13)

    FOR XML PATH(''), TYPE).value('./text()[1]', 'nvarchar(max)'), 1, 2, '')

    To fully understand the solution, please read the following articles:
    Creating a concatenated string using FOR XML

    Using CROSS APPLY VALUES to unpivot

    Thanks again for the links

  • /*
    CREATE TABLE SampleData(
    Cust_Name varchar(100),
    Prd_Name  varchar(100),
    [1/1/2019]  decimal(10, 4),
    [2/1/2019]  decimal(10, 4),
    [3/1/2019] decimal(10, 4)
    )
    INSERT INTO SampleData
    VALUES
    ('John', 'Mobile', 18.5,  45.7,  66.9),
    ('Scott', 'Laptop', 9.5,  3.7,  0);
    */

    Declare @sql varchar(max)='',@column_name varchar(max)=''

    Select @column_name =@column_name +',['+column_name+']' from INFORMATION_SCHEMA.columns where table_name ='SampleData' and COLUMN_NAME not in ('Cust_Name','Prd_Name')

    set @sql =
    '
    Select * from SampleData as a
    unpivot
    (
    Month for valu in ('+stuff(@column_name,1,1,'')+')
    ) as b'

    exec(@sql)

Viewing 8 posts - 1 through 7 (of 7 total)

You must be logged in to reply to this topic. Login to reply