【问题标题】:How do I dynamically pivot row values into columns without aggregare?如何动态地将行值旋转到没有聚合的列中?
【发布时间】:2013-07-16 04:48:05
【问题描述】:

假设我有下表代表用户调查系统的结果。

SurveyID    ResponseID  QuestionID  Answer
 --------   ----------  ----------  ------
1           1           1           'Answer 1'
1           1           2           'Answer 2'
1           1           3           'Answer 3'
1           2           1           'red'
1           2           2           'blue'
1           2           3           'green'

我想要的是如下所示的旋转输出。

SurveyID    ResponseID  Q1          Q2          Q3
--------    ----------  --          --          --
1           1           'Answer 1'  'Answer 2'  'Answer 3'
1           2           'red'       'blue'      'green'

如果始终只有相同的三个问题,我知道如何实现此目的,但此数据库托管多个调查,这些调查可能具有任意数量的唯一 QuestionID,因此我需要 Q1、Q2、Q3 列根据数量和该调查问题的 ID。

我认为这将是一个相当标准的问题,但我找不到完全满足这个问题的任何东西。任何解决方案都必须适用于 SQL Server 2005。

希望这是有道理的。谢谢。

【问题讨论】:

标签: sql tsql sql-server-2005 pivot


【解决方案1】:

1) 枢轴需要聚合。您可能事先知道您只对一行感兴趣,但 SQL 不知道这一点。如果您只处理每组一行,只需使用 MIN() 作为您的聚合。

2) 动态数据透视不是 SQL 的标准问题。这是表示层的任务,而不是数据层。您将不得不使用动态 SQL,它仍然无法处理任意数量的列,并且如果您不小心就会引发注入攻击。

如果你还想这样做:

CREATE TABLE #t (Surveyid int, Responseid int, Questionid int, Answer varchar(max))
INSERT #t VALUES (1,1,1,'Answer1'),(1,1,2,'Answer2'),(1,1,3,'Answer3'),(1,2,1,'red'),(1,2,2,'blue'),(1,2,3,'green')

DECLARE @qids nvarchar(4000)

SELECT @qids = COALESCE(@qids+',','') + qid
FROM (SELECT DISTINCT QUOTENAME(Questionid) qid FROM #t) t

EXEC ('SELECT [SurveyID],[ResponseID],'+@qids+' FROM #t PIVOT(MIN(Answer) FOR Questionid IN('+@qids+')) p')

【讨论】:

    【解决方案2】:

    好的,终于发现了如何做到这一点,所以我想分享一下。

    DECLARE @SurveyID SMALLINT;
    DECLARE @SQL as VARCHAR(MAX);
    DECLARE @Columns AS VARCHAR(MAX);
    DECLARE @ColumnHeadings AS Varchar(MAX);
    
    SET @SurveyID = 1;
    
    SELECT
        @Columns = COALESCE(@Columns + ', ','') + '[' + QuestionID + ']'
        ,@ColumnHeadings = COALESCE(@ColumnHeadings + ', ','') + '[' + QuestionID + '] AS [Q' + QuestionNumber + ']'
    FROM
    (
        SELECT DISTINCT
            CAST(a.QuestionID AS VARCHAR) AS QuestionID
            ,CASE WHEN q.QuestionNumber IS NULL THEN '' ELSE q.QuestionNumber END AS QuestionNumber
        FROM dbo.Answers AS a
        JOIN dbo.Questions AS q
            ON a.QuestionID = q.ID
        JOIN dbo.SurveyResponses AS r
            ON a.ResponseID = r.ID
        WHERE r.SurveyID = @SurveyID
    )
    
    SET @SQL = '
    WITH PivotData AS
    (
        SELECT
            a.QuestionID
            ,a.ResponseID
            ,a.Answer
        FROM dbo.Answers AS a
        JOIN dbo.SurveyResponses AS r
            ON a.ResponseID = r.ID
    )
    SELECT 
        ResponseID
    ,' + @ColumnHeadings + '
    FROM PivotData
    PIVOT
    (
        MAX(Answer)
        FOR QuestionID
        IN (' + @Columns + ')
    ) AS PivotResult
    ORDER BY ResponseID' ASC
    
    EXEC (@SQL);
    

    【讨论】:

      猜你喜欢
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-05
      • 1970-01-01
      • 2018-09-05
      • 2013-03-18
      • 1970-01-01
      相关资源
      最近更新 更多