当数据不是数字时,将行转换为列

时间:2017-03-31 23:29:56

标签: sql sql-server tsql pivot

我有一个问题表,其中包含未知数量的问题。(图中的第一个表)

我还有一个AnswerSheet表,记录了学生对问题的回答。(图中的第二个表)

enter image description here

Create table Question
(
    Id int,
    Text nvarchar(50),

    PRIMARY KEY (Id)
)

Create table AnswerSheet
(
    StudentId int,
    QuestionId int,
    Answer nvarchar(50),

    PRIMARY KEY (StudentId,QuestionId),
    FOREIGN KEY (QuestionId) REFERENCES Question (Id)
)

insert into Question
values(1,'What''s your age'),
      (2,'What''s your gender'),
      (3,'When do you go home'),
      ....


insert into AnswerSheet
values(500,1,'20'),
      (500,2,'Male'),
      (500,3,'5:00pm'),
      (501,1,'50'),
      (502,2,'I don''t know@@'),
      ....

如何编写SQL来生成这样的表?

StudentId    What's your age    What's your gender    When do you go home ...
---------    ----------------   -------------------   -------------------
500          20                 Male                  5:00pm              ...
501          50                 NULL                  NULL
502          NULL               I don''t know@@       NULL                ...

我觉得Pivot很有希望,但我不确定如何使用它,尤其是PIVOT需要聚合功能,但我的数据不是数字。

2 个答案:

答案 0 :(得分:3)

假设您想要动态

示例

Declare @SQL varchar(max) = Stuff((Select ',' + QuoteName(Text) From Question  Order by ID For XML Path('')),1,1,'') 

Select  @SQL = '
Select *
From (
        Select StudentID
              ,Col       = B.Text
              ,Value     = A.Answer
         From AnswerSheet A
         Join Question B on A.QuestionID=B.ID
     ) A
 Pivot (max(Value) For [Col] in (' + @SQL + ') ) p'
Exec(@SQL);

<强>返回

StudentID   What's your age What's your gender  When do you go home
500         20              Male               5:00pm
501         50              NULL               NULL
502         NULL            I don't know@@     NULL

如果有帮助,生成的SQL看起来像这样

Select *
From (
        Select StudentID
              ,Col       = B.Text
              ,Value     = A.Answer
         From AnswerSheet A
         Join Question B on A.QuestionID=B.ID
     ) A
 Pivot (max(Value) For [Col] in ([What's your age],[What's your gender],[When do you go home]) ) p

答案 1 :(得分:1)

我知道这个问题已经被接受了,但我希望这种方法可以帮助其他人。

您只需使用Pivot作为下一个<{1}}即可实现目标,无需使用Group by

Select  b.StudentId,
     Min(Case a.text When 'What''s your age' Then b.answer End) 'What''s your age',
     Min(Case a.text When 'What''s your gender' Then b.answer End) 'What''s your gender',
     Min(Case a.text When 'When do you go home' Then b.answer End) 'When do you go home'
from Question a inner join AnswerSheet b 
on a.id = b.Questionid
Group By StudentId

你提到未知数量的问题,所以下一个动态代码: -

DECLARE @DynamicQuestions VARCHAR(8000)

SELECT @DynamicQuestions =  Stuff(
(SELECT N' Min(Case a.text When''' + replace (Text,'''','''''')
+ ''' Then b.answer End) '''
+ replace (Text,'''','''''') + ''','
FROM Question FOR XML PATH(''),TYPE)
.value('text()[1]','nvarchar(max)'),1,1,N'')

select @DynamicQuestions = 
left(@DynamicQuestions,len(@DynamicQuestions)-1) -- for Removing last comma


exec ('Select  b.StudentId, '+ @DynamicQuestions +
'from Question a inner join AnswerSheet b
on a.id = b.Questionid
Group By StudentId' )

<强>结果: -

StudentId   What's your age What's your gender  When do you go home
500             20              Male                5:00pm
501             50              NULL                NULL
502             NULL        I don't know@@          NULL