6



SQLServerのクロス集計クエリに問題があります。

以下のようなデータがあるとします。

| 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にアクセスしてください。

4

3 に答える 3

17

PIVOT値をハードコーディングする静的な方法と、実行時に列が決定される動的な 方法の2つがあります。

動的バージョンが必要な場合でも、静的バージョンから始めて動的バージョンに移行する方が簡単な場合があります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 FiddlewithDemoを参照してください

どちらのバージョンでも同じ結果が得られます。

答えを締めくくるには、関数がない場合は、と集計関数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 FiddlewithDemoを参照してください

于 2012-09-14T10:53:59.433 に答える
1

この場合、SQLPIVOTを使用する必要があります。Pleseは次のリンクを参照してください。

不明な数の列をピボットする

SQLServerで2つ以上の列をピボットする

SQLServerの動的列を持つピボット

于 2012-09-14T10:52:35.927 に答える
0

これには、実行時にSQLクエリ文字列を作成する必要があります。SQL Serverの列名、カウント、およびデータ型は常に静的です(その最も重要な理由は、オプティマイザーが最適化時にクエリデータフローを認識している必要があることです)。

したがってPIVOT、実行時に-queryを作成し、それを実行することをお勧めしますsp_executesql。ピボット列の値をハードコーディングする必要があることに注意してください。それらを適切に脱出するように注意してください。それらのパラメータは使用できません。

または、column-countごとにそのようなクエリを1つ作成し、ピボット値にのみパラメータを使用することもできます。のようなダミーの列名を割り当てる必要がありますPivot0, Pivot1, ...。それでも、列数ごとに1つのクエリテンプレートが必要です。ピボット列の最大数(たとえば20)をクエリにハードコーディングする場合を除きます。この場合、実際には静的SQLを使用できます。

于 2012-09-14T10:49:55.943 に答える