查询以生成调查摘要(PIVOT)

时间:2012-10-04 21:49:05

标签: sql sql-server sql-server-2008 tsql pivot

我们假设我有两张桌子:

Question (Id, Text)
Answer (Value, QuestionId, Guid)

专栏Guid将来自同一个人的答案分组。

我需要一个查询来生成这样的结果:

'Question 1' | 'Question 2'
4            | 3
1            | NULL
NULL         | 5
2            | 6
9            | NULL

问题文本转换为列标题,答案值按行排列。答案按Guid分组,因此一行中有一个人的答案。如果某人没有回答特定问题,则返回NULL。

问题的数量可能会有所不同。

用于生成样本结果的数据:

 Question
 Id   | Text
 1    | Question 1
 2    | Question 2

 Answer
 Value | QuestionId | Guid
 4     | 1          | AAA
 3     | 2          | AAA
 1     | 1          | BBB
 5     | 2          | CCC
 2     | 1          | DDD
 6     | 2          | DDD
 9     | 1          | EEE

你能帮我解决一下产生结果吗?

2 个答案:

答案 0 :(得分:3)

由于您的问题数量未知,因此tou需要使用动态SQL PIVOT

DECLARE @colsFinal AS NVARCHAR(MAX),
    @colsPivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @colsFinal = STUFF((SELECT distinct ',' 
                      + QUOTENAME(Id) 
                           + ' as Question_'+ cast(Id as varchar(10))
                    from question
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

select @colsPivot = STUFF((SELECT distinct ',' 
                      + QUOTENAME(Id) 
                    from question
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT ' + @colsFinal + ' from 
             (
                select questionid, value, guid
                from question q
                left join value v
                  on q.id = v.questionid
            ) x
            pivot 
            (
                min(value)
                for questionid in (' + @colsPivot + ')
            ) p '

execute(@query)

请参阅SQL Fiddle with Demo

如果您有已知数量的列,那么您可以对PIVOT的值进行硬编码(请参阅SQL Fiddle With Demo):

select [1] as Question1, [2] as Question2
from 
(
  select questionid, value, guid
  from question q
  left join value v
    on q.id = v.questionid
) x
pivot
(
  max(value)
  for questionid in ([1], [2])
) p

或者你可以使用CASE的聚合函数(参见SQL Fiddle With Demo):

select max(case when q.id = 1 then v.value end) Question1,
  max(case when q.id = 2 then v.value end) Question2
from question q
left join value v
  on q.id = v.questionid
group by guid

答案 1 :(得分:2)

如果您不想对问题编号进行硬编码,那么您只能使用动态SQL来构建问题列表。

SQL Server dynamic PIVOT query?

对于具体问题,如果您知道他们的文本,请参阅下面的示例

create table Question(id int, text varchar(100));
insert Question select 1, 'Question 1'
union all select 2, 'The 2nd';
create table Answer(
  value int,
  questionid int,
  guid varchar(10));
insert Answer select
 4     , 1          , 'AAA' union all select
 3     , 2          , 'AAA' union all select
 1     , 1          , 'BBB' union all select
 5     , 2          , 'CCC' union all select
 2     , 1          , 'DDD' union all select
 6     , 2          , 'DDD' union all select
 9     , 1          , 'EEE';
GO
select guid, [Question 1], [The 2nd]
from (
    select guid, text, value
    from Answer A
    join Question Q on A.questionid=q.id) p
pivot (max(value) for text in ([Question 1], [The 2nd])) v