Dynamically "pivot" rows into columns - SQL Server

thiago picture thiago · Oct 5, 2016 · Viewed 6.9k times · Source

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       | [email protected]
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 | [email protected] | 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) 

Answer

Pரதீப் picture Pரதீப் · Oct 5, 2016

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', '[email protected]'),
    ('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 ║ [email protected] ║      10 ║ 99658202 ║ (915) 438-05 ║ nksnksjksj nsjsnsjjs ║
╚═════════════════════════╩══════════╩════════════════════════════╩═════════╩══════════╩══════════════╩══════════════════════╝