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

Convert row to column when data are not numbers

我有一道题目table,题数未知(图中第一个table)

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

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 来生成这样的 table?

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 需要一个聚合函数,但我的数据不是数字。

假设您想使用动态

例子

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);

Returns

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

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

只需使用 Pivot 即可实现目标 而无需 ,接下来使用 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