在SQL中将行转换为列,而不使用MAX,AVG等聚合函数

时间:2017-02-19 13:51:41

标签: sql sql-server tsql pivot unpivot

我有一张这样的表:

CREATE TABLE MyDataTable
(
     [RollNo] varchar(8), 
     [QuesBlock] int, 
     [RespVal] varchar(2)
);

INSERT INTO MyDataTable ([RollNo], [QuesBlock], [RespVal])
VALUES ('MBA0001', 1, A), ('MBA0001', 2, B), ('MBA0001', 3, D),
       ('MBA0002', 1, C), ('MBA0002', 2, A), ('MBA0002', 3, B),
       ('MBA0003', 1, B), ('MBA0003', 2, C), ('MBA0003', 3, A);

因此,我的源数据如下所示:

Source Data

现在我想达到这样的目标表结构:

enter image description here

这基本上是在针对学校的基于OMR的测试中将每个问题的候选方式,问题式答案制成表格。我在 QuesBlock 列中有固定数量的唯一值(仅 50 ),因此我可以使用硬编码。 我已经通过examples使用了pivot来实现类似的东西,但是所有这些都使用了MAX,MIN,AVG等聚合函数来处理数值。但就我而言, RESPVAL 列的值都是文本的。我该如何实现这一目标?

1 个答案:

答案 0 :(得分:3)

您可以将max()与字符/字符串一起使用。一个简单的旧样式pivot将适用于此:

select
    RollNo
  , Q1 = max(case when QuesBlock = 1 then RespVal else null end)
  , Q2 = max(case when QuesBlock = 2 then RespVal else null end)
  , Q3 = max(case when QuesBlock = 3 then RespVal else null end)
from MyDataTable
group by RollNo;

或与pivot()一样:

select
    RollNo
  , Q1
  , Q2
  , Q3
from (select RollNo, QuesBlock='Q'+convert(varchar(2),QuesBlock), RespVal
      from MyDataTable) as i
 pivot (max(RespVal) for QuesBlock in (Q1,Q2,Q3)) as p;

或动态pivot()如下:

declare @query nvarchar(max);
declare @cols nvarchar(max);

select @cols = stuff((select ','+quotename('Q'+convert(varchar(2),QuesBlock))
         from MyDataTable as C
         group by c.QuesBlock
         order by c.QuesBlock
         for xml path('')), 1, 1, '');
set @query = 'select RollNo, '+@cols+'
      from(select RollNo, QuesBlock=''Q''+convert(varchar(2),QuesBlock), RespVal
        from MyDataTable) as i
      pivot
      (
        max(RespVal)
        for QuesBlock in ('+@cols+')
      ) p';
exec sp_executesql @query;

测试设置:http://rextester.com/TURW69000

所有三个回归:

+---------+----+----+----+
| RollNo  | Q1 | Q2 | Q3 |
+---------+----+----+----+
| mba0001 | A  | B  | D  |
| mba0002 | C  | A  | B  |
| mba0003 | B  | C  | A  |
+---------+----+----+----+