我在SQL Server中使用交叉表查询时遇到问题。
假设我有以下数据:
| ScoreID | StudentID | Name | Sex | SubjectName | Score | ------------------------------------------------------------------ | 1 | 1 | Student A | Male | C | 100 | | 2 | 1 | Student A | Male | C++ | 40 | | 3 | 1 | Student A | Male | English | 60 | | 4 | 1 | Student A | Male | Database | 15 | | 5 | 1 | Student A | Male | Math | 50 | | 6 | 2 | Student B | Male | C | 77 | | 7 | 2 | Student B | Male | C++ | 12 | | 8 | 2 | Student B | Male | English | 56 | | 9 | 2 | Student B | Male | Database | 34 | | 10 | 2 | Student B | Male | Math | 76 | | 11 | 3 | Student C | Female | C | 24 | | 12 | 3 | Student C | Female | C++ | 10 | | 13 | 3 | Student C | Female | English | 15 | | 14 | 3 | Student C | Female | Database | 40 | | 15 | 3 | Student C | Female | Math | 21 | | 16 | 4 | Student D | Female | C | 17 | | 17 | 4 | Student D | Female | C++ | 34 | | 18 | 4 | Student D | Female | English | 24 | | 19 | 4 | Student D | Female | Database | 56 | | 20 | 4 | Student D | Female | Math | 43 |
我想查询显示结果如下:
| StuID| Name | Sex | C | C++ | Eng | DB | Math | Total | Average | | 1 | Student A | Male | 100| 40 | 60 | 15 | 50 | 265 | 54 | | 2 | Student B | Male | 77 | 12 | 56 | 34 | 76 | 255 | 51 | | 3 | Student C | Female | 24 | 10 | 15 | 40 | 21 | 110 | 22 | | 4 | Student D | Female | 17 | 34 | 24 | 56 | 43 | 174 | 34.8 |
我如何查询以显示这样的输出?
笔记:
主题名称:
将根据学生学习的学科而有所不同。
请访问http://sqlfiddle.com/#!6/2ba07/1来测试此查询。
有两种方法可以执行PIVOT对值进行硬编码的静态方法和执行时确定列的动态方法。
PIVOT
即使您想要一个动态版本,有时也更容易从静态版本开始,PIVOT然后朝着动态版本迈进。
静态版本:
SELECT studentid, name, sex,[C], [C++], [English], [Database], [Math], total, average from ( select s1.studentid, name, sex, subjectname, score, total, average from Score s1 inner join ( select studentid, sum(score) total, avg(score) average from score group by studentid ) s2 on s1.studentid = s2.studentid ) x pivot ( min(score) for subjectname in ([C], [C++], [English], [Database], [Math]) ) p
参见带有演示的SQL Fiddle
现在,如果您不知道将要转换的值,则可以为此使用Dynamic SQL:
DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX) select @cols = STUFF((SELECT distinct ',' + QUOTENAME(SubjectName) from Score FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'') set @query = 'SELECT studentid, name, sex,' + @cols + ', total, average from ( select s1.studentid, name, sex, subjectname, score, total, average from Score s1 inner join ( select studentid, sum(score) total, avg(score) average from score group by studentid ) s2 on s1.studentid = s2.studentid ) x pivot ( min(score) for subjectname in (' + @cols + ') ) p ' execute(@query)
两种版本将产生相同的结果。
只是为了完善答案,如果您没有PIVOT函数,则可以使用CASE和聚合函数获得此结果:
CASE
select s1.studentid, name, sex, min(case when subjectname = 'C' then score end) C, min(case when subjectname = 'C++' then score end) [C++], min(case when subjectname = 'English' then score end) English, min(case when subjectname = 'Database' then score end) [Database], min(case when subjectname = 'Math' then score end) Math, total, average from Score s1 inner join ( select studentid, sum(score) total, avg(score) average from score group by studentid ) s2 on s1.studentid = s2.studentid group by s1.studentid, name, sex, total, average