复杂的枢轴

时间:2011-05-31 22:03:36

标签: sql pivot

我已将复杂架构简化为以下示例

  

学生

  • StudentID int,Name varchar(50)
  • 1,Bill
  • 2,艾米
  • 3,Beth
  • 4,Scott
  • 5,Steve
  

  • ClassID int,Name varchar(50),Period varchar(50)
  • 1,Algebra,Period1
  • 2,地理,时期3
  • 3,Biology,Period5
  • 4,Physics,Period4
  • 5,演讲,期间2
  • 6,History,Period6

和联结表

  

StudentsClasses

  • StudentID int,ClassID int
  • 1,1
  • 1,4
  • 1,5
  • 2,6
  • 3,5
  • 3,4
  • 3,6
  • 4,1
  • 4,4
  • 5,5
  • 5,6

我的目标是列出每个学生按周期顺序列出的所选课程。我有以下选择

SELECT Name,Period1, Period2, Period3, 
    Period4, Period5, Period6  
    FROM (
SELECT _Students.Name AS [NAME],_Classes.Period AS PIVOT_CODE, _Classes.name as [Class] 
FROM _Classes 
    INNER JOIN _StudentsClasses ON _Classes.ClassID=_StudentsClasses.ClassID 
    INNER JOIN _Students ON _StudentsClasses.StudentID=_Students.StudentID
)
    AS data
    PIVOT 
    (  min([Class])  FOR [PIVOT_CODE] IN 
        (Period1, Period2, Period3, 
    Period4, Period5, Period6)
    ) AS pvt

结果是

Name   Period1   Period2   Period3   Period4   Period5   Period6
------ --------- --------- --------- --------- --------- ----------
Amy    NULL      NULL      NULL      NULL      NULL      History
Beth   NULL      Speech    NULL      Physics   NULL      History
Bill   Algebra   Speech    NULL      Physics   NULL      NULL
Scott  Algebra   NULL      NULL      Physics   NULL      NULL
Steve  NULL      Speech    NULL      NULL      NULL      History

我需要帮助的地方是我需要将所有非空值移到左列,这样就没有空白了。可以重命名列名称,例如

Name   Choice1   Choice2   Choice3   Choice4   Choice5   Choice6
------ --------- --------- --------- --------- --------- ----------
Amy    History
Beth   Speech    Physics   History
Bill   Algebra   Speech    Physics
Scott  Algebra   Physics
Steve  Speech    History

我可以通过选择一个临时表到一个临时表,然后用光标迭代每一行/列来实现这一点,但我想避免这种情况。非常感谢任何建议。

1 个答案:

答案 0 :(得分:5)

假设SQL Server 2005(至少),使用ROW_NUMBER()订购选项:

SELECT Name, Choice1, Choice2, Choice3, Choice4, Choice5, Choice6  
FROM (
    SELECT 
        S.Name AS [NAME], 
        'Choice' + CAST(ROW_NUMBER() OVER(PARTITION BY S.Name ORDER BY S.Name, C.Period) AS VARCHAR) AS PIVOT_CODE, 
         C.Name as [Class]
    FROM Classes C
        JOIN StudentsClasses SC ON C.ClassID = SC.ClassID 
        JOIN Students S ON SC.StudentID = S.StudentID
    )
    AS data
    PIVOT 
    (  min([Class])  FOR [PIVOT_CODE] IN 
        (Choice1, Choice2, Choice3, Choice4, Choice5, Choice6)
    ) AS pvt