如何透视 SQL 数据?

Posted

技术标签:

【中文标题】如何透视 SQL 数据?【英文标题】:How to Pivot the SQL Data? 【发布时间】:2019-01-09 16:57:59 【问题描述】:

我有一个与调查相关的数据集,我必须对它们创建一个视图。数据集格式为:

surveyID    RID    Question   Answer     Comment
-----------------------------------------------------------------
17     |   123  |   Q1     |   0      |
17     |   123  |   Q2     |          |   The salesperson and manager was very considerate and I will be coming back for my next car!
17     |   123  |   Q3     |   5      |   Very bad behavior

要求的结果如下

surveyID |   RID  |  Q1  |  Q1_c |  Q2  |  Q2_c  |  Q3  |  Q3_c 
-----------------------------------------------------------------
17       |   123  |  0   |       |      | The... |  5   | Very...

问题和问题评论应该在上面的标题行中:

我试图获得结果,但只有当我旋转 1 列(即答案列)时我才能成功,但如何同时旋转答案和评论列?

这是我完成的查询

select rid, surveyid, --comment,    
    Q1,Q2,Q3
from
(
  select rid, surveyid, question, --comment,    
    value
  from
  (
    select rid, surveyid, question, -- comment,
      answer      
    from #temp
  ) s
  unpivot
  (
    value
    for col in (answer)
  ) un
) src
pivot
(
  max(value)
  for question in (Q1, Q2, Q3)
) piv

结果如下:

surveyID |   RID  |  Q1  |  Q2  |  Q3  |  
-----------------------------------------------------------------
17       |   123  |  0   |      |  5   | 

【问题讨论】:

您是否尝试过从答案中旋转单独的子查询/CTE 中的 cmets,然后将两个子查询/CTE 连接在一起? 【参考方案1】:

这是另一种选择,因为 SQL Server 没有简单的方法来使用枢轴运算符执行多列枢轴,所以您始终可以恢复为执行手动编码的枢轴"

select surveyID, rid
     , max(case question when 'Q1' then answer end) q1
     , max(case question when 'Q1' then comment end) q1_c
     , max(case question when 'Q2' then answer end) q2
     , max(case question when 'Q2' then comment end) q2_c
     , max(case question when 'Q3' then answer end) q3
     , max(case question when 'Q3' then comment end) q3_c
  from #temp
 group by surveyID, rid

它实际上比目前提供的其他选项更紧凑,并且可能具有更好的性能,尽管您需要自己测试该断言。

【讨论】:

【参考方案2】:

我将查询拆分为两个相似的枢轴,在 CTE 中枢轴数据,然后将 CTE 连接在一起。

;WITH QnA AS
(
    SELECT
        RID
        ,surveyID
        ,Q1
        ,Q2
        ,Q3
    FROM
    ( SELECT RID, surveyID, Question, Answer FROM #temp ) src
    PIVOT
    (
        MAX(Answer)
        FOR Question IN ( Q1
            ,Q2
            ,Q3
        )
    ) piv
)
,QnAComments AS
(
    SELECT
        RID
        ,surveyID
        ,Q1_c = Q1
        ,Q2_c = Q2
        ,Q3_c = Q3
    FROM
    ( SELECT RID, surveyID, Question, Comment FROM #temp ) src
    PIVOT
    (
        MAX(Comment)
        FOR Question IN ( Q1
            ,Q2
            ,Q3
        )
    ) piv
)
SELECT
    QnA.surveyID
    ,QnA.RID
    ,Q1
    ,Q1_c
    ,Q2
    ,Q2_c
    ,Q3
    ,Q3_c
FROM QnA
INNER JOIN QnAComments ON QnAComments.RID = QnA.RID
                           AND QnAComments.surveyID = QnA.surveyID

【讨论】:

【参考方案3】:

当您取消透视数据时,您可以将 question 和 Col 列组合成一个列,以便在透视操作中使用,如下所示:

select * from (
  select surveyid, rid, question+'_'+col QC, value from (
    select rid, surveyid, question, Comment,
      cast(answer as varchar(91)) Answer
    from #temp
  ) s
  unpivot
  (
    value
    for col in (Answer, Comment)
  ) un
  ) src
 pivot
(
  max(value)
  for QC in (Q1_Answer, Q1_Comment, Q2_Answer, Q2_Comment, Q3_Answer, Q3_Comment)
) piv

您可以通过一些小的调整来获得所需的列标题:

select * from (
  select surveyid, rid, question+case col when 'comment' then '_c' end QC, value from (
    select rid, surveyid, question, Comment,
      cast(answer as varchar(91)) Answer
    from #temp
  ) s
  unpivot
  (
    value
    for col in (Answer, Comment)
  ) un
  ) src
 pivot
(
  max(value)
  for QC in (Q1, Q1_C, Q2, Q2_C, Q3, Q3_C)
) piv

【讨论】:

以上是关于如何透视 SQL 数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何将公式写入数据透视表 SQL?

如何在 SQL/DB2 中使用数据透视?

如何在 Transact/SQL 中创建数据透视表?

SQL 数据透视表动态

Postgresql 如何在 SQL 数据库上透视表

如何获得从 sql 到 vb 的动态数据透视