Search code examples
sqlsql-servert-sqldynamicunpivot

Transform Columns to Rows dynamically using T-SQL


I have the following table where I need to transform Columns to Rows

tbl_Survey:

      SurveyID   Quest_1  Quest_2  Quest_3
             7        1         1        1
             8        2         2        2
             9        3         3        3
     
 

I need to have the following result:

       SurveyID  Questions  Rating 
              7    Quest_1      1
              7    Quest_2      1
              7    Quest_3      1
              8    Quest_1      2
              8    Quest_2      2
              8    Quest_3      2
              9    Quest_1      3
              9    Quest_2      3
              9    Quest_3      3 
    

To have this result I used the following code:

       SELECT [SurveyID], [Question], [Rating]
       FROM [dbo].[tbl_Survey]

       UNPIVOT
        (
         [Rating]
          FOR [Question] in ([Quest_1], [Quest_2], [Quest_3])
        ) AS SurveyUnpivot

But, my Quest_1, Quest_2, Quest_3 values could potentially be changed / or even added a new once...

Are there ways to code them, so it can be used for any text values (not only for Quest_1 2 3)? Not necessary with the UNPIVOT... Could be any other way

Thank you


Solution

  • You need to make a dynamic UNPIVOT. Check the example below:

    DROP TABLE IF EXISTS [dbo].[DataSource];
    
    CREATE TABLE [dbo].[DataSource]
    (
        [SurveyID] INT
       ,[Quest_1] INT
       ,[Quest_2] INT
       ,[Quest_3] INT
    );
    
    INSERT INTO [dbo].[DataSource] ([SurveyID], [Quest_1], [Quest_2], [Quest_3])
    VALUES (7, 1, 1, 1)
          ,(8, 2, 2, 2)
          ,(9, 3, 3, 3);
    
    GO
    
    DECLARE @DynamicTSQLStatement NVARCHAR(MAX);
    DECLARE @DynamicTSQLUnpivotColumns NVARCHAR(MAX);
    
    SET @DynamicTSQLUnpivotColumns = STUFF
    (
        (
            SELECT ',' + QUOTENAME([name])
            FROM [sys].[columns]
            WHERE [object_id] = OBJECT_ID('[dbo].[DataSource]')
                AND [name] <> 'SurveyID'
            ORDER BY [name]
            FOR XML PATH(''), TYPE
        ).value('.', 'VARCHAR(MAX)')
        ,1
        ,1
        ,''
    );
    
    SET @DynamicTSQLStatement = N'
    SELECT [SurveyID], [Question], [Rating]
    FROM [dbo].[DataSource]
    UNPIVOT
    (
        [Rating] FOR [Question] in (' + @DynamicTSQLUnpivotColumns + ')
    ) AS SurveyUnpivot';
    
    EXEC sp_executesql @DynamicTSQLStatement;