Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Zapytanie krzyżowe z dynamicznymi kolumnami w SQL Server 2005 do góry

Istnieją dwa sposoby wykonania PIVOT statyczne, gdzie na stałe zakodujesz wartości i dynamiczne, gdzie kolumny są określane podczas wykonywania.

Nawet jeśli będziesz potrzebować wersji dynamicznej, czasami łatwiej jest zacząć od statycznego PIVOT a następnie pracuj nad dynamicznym.

Wersja statyczna:

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

Zobacz SQL Fiddle z demonstracją

Teraz, jeśli nie znasz wartości, które zostaną przekształcone, możesz użyć do tego dynamicznego 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)

Zobacz Skrzypce SQL z wersją demonstracyjną

Obie wersje przyniosą takie same wyniki.

Aby uzupełnić odpowiedź, jeśli nie masz PIVOT funkcji, możesz uzyskać ten wynik za pomocą CASE oraz funkcja agregująca:

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

Zobacz Skrzypce SQL z wersją demonstracyjną



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Czy SQL Server gwarantuje sekwencyjne wstawianie kolumny tożsamości?

  2. Dlaczego klauzula „Top” może prowadzić do długotrwałych kosztów

  3. Kiedy lepiej przechowywać flagi jako maskę bitową zamiast używać tabeli asocjacyjnej?

  4. Czy lepiej zrobić equi łączyć w klauzuli from czy klauzula where?

  5. Zapytanie SQL, aby znaleźć nazwę kolumny w całej bazie danych