【问题标题】:Tricky SQL Server Pivot Table for Survey用于调查的棘手 SQL Server 数据透视表
【发布时间】:2012-12-11 22:28:13
【问题描述】:

我有一个包含以下数据的 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 值被忽略,正确答案放在列中。我查看了数据透视表示例,但它们似乎专注于单列数据透视表。

【问题讨论】:

    标签: sql sql-server tsql pivot unpivot


    【解决方案1】:

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

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

    静态枢轴:

    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

    动态枢轴:

    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 和一个聚合函数以及CASEPIVOT

    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
    

    SQL Fiddle with Demo

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

    | CLIENTID | SURVEYID |  Q1 | Q2 | Q3 |
    ---------------------------------------
    |        1 |        1 | Yes | 18 | 19 |
    |        2 |        1 |  No | 18 | 19 |
    |        3 |        2 | Yes | 15 | 13 |
    

    【讨论】:

    • 感谢您的快速回复...虽然数据类型不匹配。我尝试对 q_optionID 进行强制转换或转换,但它并没有真正起作用。
    • @TehFoobar 请看我对UNPIVOT的编辑,数据类型必须相同
    • “question_OptionID”列的类型与UNPIVOT列表中指定的其他列的类型冲突。
    • @TehFoobar 你看到我的改变和这个演示了吗? -- sqlfiddle.com/#!3/c042f/5
    【解决方案2】:

    没有显式反透视的示例。不过,这仍然是一个非常有用的技术!

    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

    【讨论】:

      【解决方案3】:
      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

      【讨论】:

        猜你喜欢
        • 2023-03-23
        • 2019-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-25
        • 2012-02-22
        • 1970-01-01
        相关资源
        最近更新 更多