Search code examples
sqlsql-serverpivotpivot-tabledynamic-pivot

Dynamically "pivot" rows into columns - SQL Server


I have a table that looks like this:

DtCreated               | UserName | Question    | Answer
2016-09-24 14:30:11.927 | mauricio | Senha       | 99658202
2016-09-24 14:30:11.927 | mauricio | Inteiro     | 10
2016-09-24 14:30:11.927 | mauricio | Telefone    | (915) 438-05
2016-09-24 14:30:11.927 | mauricio | Email       | mauriiciobarbosa@gmail.com
2016-09-24 14:30:11.927 | mauricio | Texto Livre | nksnksjksj nsjsnsjjs
2016-09-24 14:30:11.927 | mauricio | Decimal     | 0.9

How can I use pivot to transform this data into this?

DtCreated               | UserName | Senha    | Inteiro | Telefone     | Email                      | Texto Livre          | Decimal
2016-09-24 14:30:11.927 | mauricio | 99658202 |  10     | (915) 438-05 | mauriiciobarbosa@gmail.com | nksnksjksj nsjsnsjjs | 0.9

PS: "Question" column has dynamically created values and data should be grouped by "DtCreated" and "Username" fields.

This is the SQL code i'm using right now:

SELECT 

sf.[DtCreated],    
sf.[UserName],
fc.Title as Question,
sv.Value as Answer

  FROM [form].[SubmissionForm] sf
  inner join [form].[Submission] s on
  sf.id = s.SubmissionForm_Id
  inner join [form].[FormComponent] fc on s.FormComponentId = fc.Id
  inner join [form].[SubmissionValue] sv on s.Id = sv.Submission_Id
  where sf.Id = '0DBA8590-C33E-48F8-9E64-C68EEFC536FF'
  order by sf.[DtCreated]

I've found some dynamic pivot examples but could not fit them into my specific case. Any help would be appreciated. Thanks.

EDIT:

Thanks to Prdp, I'm almost there. This is the dynamic pivot code 'til now:

DECLARE @sql      VARCHAR(max)='', 
        @col_list VARCHAR(8000)='' 

SET @col_list = (SELECT DISTINCT Quotename(fc.Title) + ',' 
                 FROM   [form].[SubmissionForm] sf
  inner join [form].[Submission] s on
  sf.id = s.SubmissionForm_Id
  inner join [form].[FormComponent] fc on s.FormComponentId = fc.Id
  inner join [form].[SubmissionValue] sv on s.Id = sv.Submission_Id
                 FOR xml path('')) 

SET @col_list = LEFT (@col_list, Len(@col_list) - 1) 

SET @sql = 'select [DtCreated],[UserName]' + @col_list 
           + ' from (SELECT 

sf.[DtCreated],    
sf.[UserName],
fc.Title,
sv.Value

  FROM [form].[SubmissionForm] sf
  inner join [form].[Submission] s on
  sf.id = s.SubmissionForm_Id
  inner join [form].[FormComponent] fc on s.FormComponentId = fc.Id
  inner join [form].[SubmissionValue] sv on s.Id = sv.Submission_Id
) pivot (max([sv.Value]) for [fc.Title] in (' 
           + @col_list + '))pv' 

EXEC(@sql) 

Solution

  • Here is one way to do it using Dynamic Pivot

    DECLARE @sql      VARCHAR(max)='', 
            @col_list VARCHAR(8000)='' 
    
    SET @col_list = (SELECT DISTINCT Quotename([question]) + ',' 
                     FROM   Yourquery
                     FOR xml path('')) 
    
    SET @col_list = LEFT (@col_list, Len(@col_list) - 1) 
    
    SET @sql = 'select [DtCreated],[UserName]' + @col_list 
               + ' from Yourquery pivot (max([Answer]) for [Question] in (' 
               + @col_list + '))pv' 
    
    EXEC(@sql) 
    

    Update : You are missing Alias name to the sub-select

    SET @sql = 'select [DtCreated],[UserName]' + @col_list 
               + ' from (SELECT 
    
    sf.[DtCreated],    
    sf.[UserName],
    fc.Title,
    sv.Value
    
      FROM [form].[SubmissionForm] sf
      inner join [form].[Submission] s on
      sf.id = s.SubmissionForm_Id
      inner join [form].[FormComponent] fc on s.FormComponentId = fc.Id
      inner join [form].[SubmissionValue] sv on s.Id = sv.Submission_Id
    ) a --here
    pivot (max([sv.Value]) for [fc.Title] in (' 
               + @col_list + '))pv' 
    
    EXEC(@sql) 
    

    DEMO :

    Schema setup

    CREATE TABLE #Table1
        ([DtCreated] datetime, [UserName] varchar(8), [Question] varchar(11), [Answer] varchar(26))
    ;
    
    
    INSERT INTO #Table1
        ([DtCreated], [UserName], [Question], [Answer])
    VALUES
        ('2016-09-24 14:30:11', 'mauricio', 'Senha', '99658202'),
        ('2016-09-24 14:30:11', 'mauricio', 'Inteiro', '10'),
        ('2016-09-24 14:30:11', 'mauricio', 'Telefone', '(915) 438-05'),
        ('2016-09-24 14:30:11', 'mauricio', 'Email', 'mauriiciobarbosa@gmail.com'),
        ('2016-09-24 14:30:11', 'mauricio', 'Texto Livre', 'nksnksjksj nsjsnsjjs'),
        ('2016-09-24 14:30:11', 'mauricio', 'Decimal', '0.9')
    ;
    

    Query :

    declare @sql varchar(max)='',@col_list varchar(8000)=''
    
    set @col_list = (select distinct quotename([Question])+',' from #Table1
    for xml path(''))
    
    set @col_list = left (@col_list,len(@col_list)-1)
    
    set @sql = 'select [DtCreated],[UserName]'+@col_list+' from
    #Table1
    pivot (max([Answer]) for [Question] in ('+@col_list+'))pv'
    
    exec(@sql)
    

    Result :

    ╔═════════════════════════╦══════════╦════════════════════════════╦═════════╦══════════╦══════════════╦══════════════════════╗
    ║        DtCreated        ║ Decimal  ║           Email            ║ Inteiro ║  Senha   ║   Telefone   ║     Texto Livre      ║
    ╠═════════════════════════╬══════════╬════════════════════════════╬═════════╬══════════╬══════════════╬══════════════════════╣
    ║ 2016-09-24 14:30:11.000 ║ mauricio ║ mauriiciobarbosa@gmail.com ║      10 ║ 99658202 ║ (915) 438-05 ║ nksnksjksj nsjsnsjjs ║
    ╚═════════════════════════╩══════════╩════════════════════════════╩═════════╩══════════╩══════════════╩══════════════════════╝