格式化从动态数据透视获得的锯齿状数据

时间:2015-01-08 14:36:20

标签: sql sql-server pivot

我需要格式化并从数据库中提取一些数据。虽然我可以成功地提取数据,但我正在努力解决它的锯齿状性质。

我所拥有的是以下内容:

create table temp
(
    QuestionID INT,
    AnswerID INT,
    AnswerValue NVARCHAR(50)
)

insert into temp values (1, 1, 'Ans C')
insert into temp values (1, 2, 'Ans B')
insert into temp values (1, 3, 'Ans A')
insert into temp values (2, 4, 'Ans D')
insert into temp values (2, 5, 'Ans E')

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

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(c.AnswerID) 
            FROM temp c
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT QuestionID, ' + @cols + ' from 
            (
                select QuestionID
                    , AnswerValue
                    , AnswerID
                from temp
           ) x
            pivot 
            (
                max(AnswerValue)
                for AnswerID in (' + @cols + ')
            ) p '


execute(@query)

drop table temp

执行此生成

+------------+-------+-------+-------+-------+-------+
| QuestionID |   1   |   2   |   3   |   4   |   5   |
+------------+-------+-------+-------+-------+-------+
|          1 | Ans C | Ans B | Ans A | NULL  | NULL  |
|          2 | NULL  | NULL  | NULL  | Ans D | Ans E |
+------------+-------+-------+-------+-------+-------+

我只需要像这样格式化它

+------------+-------+-------+-------+
| QuestionID |  Q1   |  Q2   |  Q3   |
+------------+-------+-------+-------+
|          1 | Ans C | Ans B | Ans A |
|          2 | NULL  | Ans D | Ans E |
+------------+-------+-------+-------+

注意由于限制,这需要在SQL中完成,而不是像c#。

这样的高级语言

2 个答案:

答案 0 :(得分:1)

代码有些问题。首先,您使用AnswerID创建列列表,以便将数据拆分为多个列而不是每个问题的答案。

为了解决这个问题,你需要使用像row_number()这样的窗口函数来为每个问题/答案组合创建一个序列。

创建动态列时,请将代码更改为:

SET @cols = STUFF((SELECT ',' + QUOTENAME('Q'+cast(rn as varchar(10))) 
            FROM
            (
              SELECT rn = row_number() over(partition by QuestionID
                                             order by AnswerID) 
              FROM temp
            ) c
            group by rn
            order by rn
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

这将使用row_number(),并将根据QuestionID创建列名。然后,您将在您的子查询中包含row_number()来制作代码:

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

SET @cols = STUFF((SELECT ',' + QUOTENAME('Q'+cast(rn as varchar(10))) 
            FROM
            (
              SELECT rn = row_number() over(partition by QuestionID
                                             order by AnswerID) 
              FROM temp
            ) c
            group by rn
            order by rn
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = 'SELECT QuestionID, ' + @cols + ' 
           from 
           (
                select QuestionID
                  , AnswerValue
                  , col = ''Q''+ cast(row_number() over(partition by QuestionID
                                                         order by AnswerID) as varchar(10))
                from temp
           ) x
            pivot 
            (
                max(AnswerValue)
                for col in (' + @cols + ')
            ) p '

exec sp_executesql @query;

请参阅SQL Fiddle with Demo.这会给出结果:

| QUESTIONID |    Q1 |    Q2 |     Q3 |
|------------|-------|-------|--------|
|          1 | Ans C | Ans B |  Ans A |
|          2 | Ans D | Ans E | (null) |

答案 1 :(得分:1)

您可以使用以下代码:

SELECT 'A' + CAST(ROW_NUMBER() OVER(PARTITION BY QuestionID ORDER BY Answer) AS VARCHAR(10)) AS cName
FROM tblAnswers

以生成所需的列名。上面给你的是:

cName
-----
A1
A2
A3
A1
A2

您可以随后在动态数据透视中使用上述内容来获得所需的结果:

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

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(a.cName) 
                   FROM (
                      SELECT 'A' + CAST(ROW_NUMBER() OVER(PARTITION BY QuestionID ORDER BY Answer) AS VARCHAR(10)) AS cName
                      FROM tblAnswers
                   ) a
                   FOR XML PATH(''), TYPE
                  ).value('.', 'NVARCHAR(MAX)'),1,1,'')

set @query = 'SELECT Question, ' + @cols + ' ' +
             'FROM (
                SELECT q.Question, a.Answer,
                       ''A'' + CAST(ROW_NUMBER() OVER(PARTITION BY a.QuestionID ORDER BY Answer) AS VARCHAR(10)) AS cName
                FROM tblAnswers AS a
                INNER JOIN tblQuestions AS q ON a.QuestionID = q.QuestionID 
              ) t 
              PIVOT
              (
                 MAX(t.Answer)
                 FOR cName in (' + @cols + ')
              ) Pvt '

execute(@query)

上面的输出如下:

Question    A1      A2       A3
-----------------------------------
Q1          Answer1 Answer2 Answer3
Q2          Answer4 Answer5 NULL

SQL Fiddle demo here