【问题标题】:Query to produce survey summary (PIVOT)查询以生成调查摘要 (PIVOT)
【发布时间】:2012-10-04 21:49:04
【问题描述】:

假设我有两张桌子:

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

您能帮我查询一下以产生结果吗?

【问题讨论】:

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


    【解决方案1】:

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

    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
    

    【讨论】:

    • 嗯,这太疯狂了.. 你是怎么这么快就写出这么多东西的? :)
    • 第一个 SQL Fiddle 示例正是我所需要的,谢谢!但是,我没有得到一件事.. Guid 分组如何在您的查询中起作用?我看不到与此相关的任何内容。
    • @jakubka 在最后一个查询中起作用,因为它会生成所有行。如果您删除GROUP BY Guid,您只会得到一个结果。如果您从SELECT 语句中排除GUID,也会发生同样的事情,只会出现一行。您需要使值不同,因为有一个聚合函数,GUID 就是这样做的。 :)
    • 我现在明白了!再次感谢。
    【解决方案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
    

    【讨论】:

    • 谢谢!我没有意识到我可以使用像 max 这样的无害函数来获取单个值。 :) 不过,问题的数量是完全未知的,所以恐怕我被动态 SQL 卡住了.. 还是谢谢你!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多