用于调查的棘手的SQL Server数据透视表

时间:2012-12-11 22:28:13

标签: sql sql-server tsql pivot unpivot

我有一个包含以下数据的SQL Server视图:

ID   clientID  surveyID    questionID     q_optionID   q_ans_text
-----------------------------------------------------------------
1       1          1           1            NULL            Yes
2       1          1           2             18             NULL 
3       1          1           3             19             NULL
4       2          1           1            NULL             No
5       2          1           2             18             NULL
6       2          1           3             19             NULL
7       3          2           1            NULL            Yes 
8       3          2           2             15             NULL 
9       3          2           3             13             NULL   

我希望结果是这样的:

ClientID  SurveyID   Q1    Q2    Q3  
------------------------------------
   1          1     Yes    18    19   
   2          1      No    18    19   
   3          2     Yes    15    13 

忽略条件NULL值并在列中放置正确答案。我看过Pivot表的例子,但他们似乎专注于单列支点。

3 个答案:

答案 0 :(得分:3)

要执行此转换,您需要UNPIVOT,然后PIVOT数据。 UNPIVOT将获取q_optionIDq_ans_text列中的值,并将其转换为两列,其中包含值和列名称。

有两种方法可以PIVOT这个,您可以使用静态版本对所有值进行硬编码,也可以使用动态sql。为了UNPIVOT数据,您需要确保数据具有相同的数据类型,因此可能需要进行转换。

静态PIVOT:

select clientid, surveyid, 
    questionid,
    value,
    col
  from
  (
    select clientid, surveyid, questionid,
      cast(q_optionID as varchar(4)) q_optionID,
      q_ans_text
    from yourtable
  ) s
  unpivot
  (
    value
    for col in (q_optionID, q_ans_text)
  ) un

请参阅SQL Fiddle with Demo

取消透露结果:

| CLIENTID | SURVEYID | QUESTIONID | VALUE |        COL |
---------------------------------------------------------
|        1 |        1 |          1 |   Yes | q_ans_text |
|        1 |        1 |          2 |    18 | q_optionID |
|        1 |        1 |          3 |    19 | q_optionID |
|        2 |        1 |          1 |    No | q_ans_text |
|        2 |        1 |          2 |    18 | q_optionID |
|        2 |        1 |          3 |    19 | q_optionID |
|        3 |        2 |          1 |   Yes | q_ans_text |
|        3 |        2 |          2 |    15 | q_optionID |
|        3 |        2 |          3 |    13 | q_optionID |

然后,您将PIVOT应用于结果以获得最终产品。

select *
from
(
  select clientid, surveyid, 
    'Q'+cast(questionid as varchar(10)) question,
    value
  from
  (
    select clientid, surveyid, questionid,
      cast(q_optionID as varchar(4)) q_optionID,
      q_ans_text
    from yourtable
  ) s
  unpivot
  (
    value
    for col in (q_optionID, q_ans_text)
  ) un
) src
pivot
(
  max(value)
  for question in (Q1, Q2, Q3)
) piv

请参阅SQL Fiddle with demo

动态PIVOT:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME('Q'+cast(questionid as varchar(10))) 
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT clientid, surveyid,' + @cols + ' from 
             (
                select clientid, surveyid, 
                  ''Q''+cast(questionid as varchar(10)) question,
                  value
                from
                (
                  select clientid, surveyid, questionid,
                    cast(q_optionID as varchar(4)) q_optionID,
                    q_ans_text
                  from yourtable
                ) s
                unpivot
                (
                  value
                  for col in (q_optionID, q_ans_text)
                ) un
            ) x
            pivot 
            (
                max(value)
                for question in (' + @cols + ')
            ) p '

execute(@query)

请参阅SQL Fiddle with Demo

UNION ALL /与案例版本汇总:

现在,如果您在没有PIVOT的系统中工作,那么您可以使用UNION ALLUNPIVOT以及使用CASE到{的汇总函数{1}}:

PIVOT

请参阅SQL Fiddle with Demo

这三个都会产生相同的结果:

select clientid, surveyid,
  max(case when questionid = 1 then value end) Q1,
  max(case when questionid = 2 then value end) Q2,
  max(case when questionid = 3 then value end) Q3
from
(
  select clientid, surveyid, questionid, cast(q_optionID as varchar(10)) value, 'q_optionID' col
  from yourtable
  union all
  select clientid, surveyid, questionid, q_ans_text value, 'q_ans_text' col
  from yourtable
) unpiv
group by clientid, surveyid

答案 1 :(得分:1)

没有显式unpivot的示例。尽管如此,仍然是一个非常有用的技术!

Select
  clientID, 
  SurveyID, 
  [1] as Q1, 
  [2] as Q2,
  [3] as Q3
From (
  Select
    clientID,
    surveyID,
    questionID,
    IsNull(Cast(q_optionID as varchar(10)), q_ans_text) answer
  From
    Answers
) a
Pivot (
  Max(answer)
  For questionID In ([1], [2], [3])
) p

http://sqlfiddle.com/#!6/8552a/8

答案 2 :(得分:0)

select
  clientid, surveyid,
  max(case when questionid = 1 then coalesce(q_ans_text, cast(q_optionID as char)) else null end) as Q1,
  max(case when questionid = 2 then coalesce(q_ans_text, cast(q_optionID as char)) else null end) as Q2,
  max(case when questionid = 3 then coalesce(q_ans_text, cast(q_optionID as char)) else null end) as Q3
 from yourtable
 group by clientid, surveyid

http://sqlfiddle.com/#!18/9163ba/11