sql >> Databasteknik >  >> RDS >> Sqlserver

Korstabellfråga med dynamiska kolumner i SQL Server 2005 upp

Det finns två sätt att utföra en PIVOT statisk där du hårdkodar värdena och dynamisk där kolumnerna bestäms när du kör.

Även om du vill ha en dynamisk version är det ibland lättare att börja med en statisk PIVOT och arbeta sedan mot en dynamisk.

Statisk version:

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

Se SQL-fiol med demo

Nu, om du inte känner till värdena som kommer att transformeras kan du använda Dynamic SQL för detta:

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)

Se SQL-fiol med demo

Båda versionerna kommer att ge samma resultat.

Bara för att avrunda svaret, om du inte har en PIVOT funktion, då kan du få detta resultat med CASE och en aggregerad funktion:

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

Se SQL-fiol med demo



  1. Få MySQL auto-increment id (om) att börja från 1

  2. Hur lägger man till 2 punkter med avstånd mellan dem (SRID =32636)?

  3. Räkna icke-tomma fält mysql

  4. Postgres-kolumnen finns inte