不同列和多列上的T-SQL Dynamic Pivot

时间:2017-07-07 16:32:52

标签: sql sql-server-2008 tsql pivot

表学生:

Studid      StuName     
=========================
1           'Marco Polo'
2           'Leroy Jenkins'

表科目:

Subid      SubName     
===================
1           English
2           French
3           German
4           Math
5           Physics

表等级

Stuid      Subid          Grade1            Grade2
==================================================
1           1                10               6    
1           2                9                7    
2           1                8                4    
2           4                7                9    
2           5                6                10   

我想实现2个表: 表1:

StuName      English 1      English 2      French 1       French 2
==================================================================
'Marco Polo'     10             6              9              7

表1:

StuName      English 1      English 2      Math 1       Math 2      Physics 1       Physics 2
==================================================================
'Leroy Jenkins'    8             4              7              9    6              10

1 个答案:

答案 0 :(得分:0)

在您的示例中,Student上的ID为StudId,而Grades中的ID为StuId。这可能是也可能不是拼写错误,但我把它留作了贴子。

您需要unpivot主题+ gradenumber(我在下面的代码中使用cross apply(values... )方法unpivot,但union allunpivot()版本会也工作),然后转动。

由于您只想返回特定于每个学生的列,因此您可以在列列表生成和pivot的内部查询中使用过滤器,并将该参数传递给sp_executesql以执行生成的代码。

declare @cols nvarchar(max), @sql nvarchar(max), @StuId int;
set @StuId = 2;
set @cols = stuff((
    select ', ' + quotename(sub.subName+'1')+', '+ quotename(sub.subName+'2')
    from Grades g
      inner join Student stu
        on g.StuId = stu.StudId
      inner join Subjects sub 
        on g.SubId = sub.SubId
    where stu.StudId = @StuId
    order by 1
    for xml path (''), type).value('(./text())[1]','nvarchar(max)')
    ,1,2,'');
set @sql = '
    select StuName, '+ @cols +'
    from (
      select stu.StuName, u.SubName, u.Grade
      from Grades g
        inner join Student stu
          on g.StuId = stu.StudId
        inner join Subjects sub 
          on g.SubId = sub.SubId
        cross apply (values 
            (sub.SubName+''1'', g.Grade1)
          , (sub.SubName+''2'', g.Grade2)
          )u (SubName,Grade) 
      where stu.StudId = @StuId
      ) as t
    pivot (sum(Grade) for SubName in (' + @cols +')) p';

select CodeGenerated = @sql;
exec sp_executesql @sql ,N'@StuId int', @StuId;

rextester演示:http://rextester.com/DCLY81531

返回CodeGenerated

select StuName, [English1], [English2], [Math1], [Math2], [Physics1], [Physics2]
    from (
      select stu.StuName, u.SubName, u.Grade
      from Grades g
        inner join Student stu
          on g.StuId = stu.StudId
        inner join Subjects sub 
          on g.SubId = sub.SubId
        cross apply (values 
            (sub.SubName+'1', g.Grade1)
          , (sub.SubName+'2', g.Grade2)
          )u (SubName,Grade) 
      where stu.StudId = @StuId
      ) as t
    pivot (sum(Grade) for SubName in ([English1], [English2], [Math1], [Math2], [Physics1], [Physics2])) p

for @StuId = 2返回:

+---------------+----------+----------+-------+-------+----------+----------+
|    StuName    | English1 | English2 | Math1 | Math2 | Physics1 | Physics2 |
+---------------+----------+----------+-------+-------+----------+----------+
| Leroy Jenkins |        8 |        4 |     7 |     9 |        6 |       10 |
+---------------+----------+----------+-------+-------+----------+----------+

for @StuId = 1返回:

+------------+----------+----------+---------+---------+
|  StuName   | English1 | English2 | French1 | French2 |
+------------+----------+----------+---------+---------+
| Marco Polo |       10 |        6 |       9 |       7 |
+------------+----------+----------+---------+---------+