交叉表查询在SQL Server 2005中了动态列(Crosstab Query with Dyn

2019-07-31 13:57发布



我在与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  |

我怎么能查询显示这样的输出?

注意:

课题名称:

  • C
  • C ++
  • 英语
  • 数据库
  • 数学

    将被改变取决于其受学生学习。

请到http://sqlfiddle.com/#!6/2ba07/1测试此查询。

Answer 1:

有两种方法来执行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拨弄演示

现在,如果你不知道会被转化,那么你可以使用动态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)

请参阅SQL拨弄演示

两个版本都将产生相同的结果。

只是让这个答案,如果你没有一个PIVOT功能,那么你就可以用得到这个结果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

请参阅SQL拨弄演示



Answer 2:

你需要使用SQL PIVOT在这种情况下。 普莱舍参考以下链接:

透视在列的未知号码

透视两个或在SQL Server的详细列

在SQL Server中动态列支点



Answer 3:

这需要建立在运行时一个SQL查询字符串。 列名,计数和数据类型在SQL Server总是静态的(对于最重要的原因是优化程序必须知道在优化时间查询数据流)。

所以,我建议你建立一个PIVOT在运行时-查询,并通过运行sp_executesql 。 请注意,您必须硬编码枢轴列值。 要小心,适当地排除它们。 不能使用参数他们。

或者你可以建立每列数和使用参数,一个这样的查询只为支点的值。 你将不得不像分配一些虚拟列名Pivot0, Pivot1, ... 。 不过,你需要每列数一个查询模板。 除非你愿意硬编码枢轴列到查询的最大数目(比方说20)。 在这种情况下,你实际上可以使用静态SQL。



文章来源: Crosstab Query with Dynamic Columns in SQL Server 2005 up