如何利用T-SQL來做到類似Excel的樞紐分析表

如何利用T-SQL來做到類似Excel的樞紐分析表,本文將利用PIVOT關係運算子來實作。

假設我有三個資料表分別是Students、Subjects及Scores,用來存放學生資料、科目資料及考試成績資料(如下圖),若考試成績未達60分,則必須參加補考,考到及格為止。

image

 

因此我們可能以下列T-SQL來取得每個學生每一科的最高分數:

   1:  select t2.Name as StudentName,t3.Name as SubjectName
   2:              ,MAX(t1.Score) as MaxScore
   3:  from dbo.Scores t1
   4:  inner join dbo.Students t2 
   5:      on t1.StudentID = t2.StudentID
   6:  inner join dbo.Subjects t3
   7:      on t1.SubjectID = t3.SubjectID
   8:  group by t2.Name,t3.Name
   9:  order by t2.Name,t3.Name

 

執行結果如下:

image

 

若我們想把每個學生的每一科目變成是資料行,如同EXCEL的樞紐分析表一樣(如下圖),在SQL Server 2005以後的版本,可以利用Pivot關係運算子來完成。

 

image

 

以下為Pivot的語法:

   1:  SELECT <非樞紐資料行>,
   2:   
   3:      [第一個樞紐資料行] AS <資料行名稱>,
   4:   
   5:      [第二個樞紐資料行] AS <資料行名稱>,
   6:   
   7:      ...
   8:   
   9:      [最後一個樞紐資料行] AS <資料行名稱>
  10:   
  11:  FROM
  12:   
  13:      (<產生資料的 SELECT 查詢>)
  14:   
  15:      AS <來源查詢的別名>
  16:   
  17:  PIVOT
  18:   
  19:  (
  20:   
  21:      <彙總函式>(<要彙總的資料行>)
  22:   
  23:  FOR
  24:   
  25:  [<包含將變成資料行標頭之值的資料行>]
  26:   
  27:      IN ( [第一個樞紐資料行], [第二個樞紐資料行],
  28:   
  29:      ... [最後一個樞紐資料行])
  30:   
  31:  ) AS <樞紐分析表的別名>
  32:   
  33:  <選擇性的 ORDER BY 子句>;

 

首先準備以下列T-SQL來準備Pivot關係運算子所需要的原始資料:

   1:  select t2.Name as StudentName,t3.Name as SubjectName,t1.Score
   2:  from dbo.Scores t1
   3:  inner join dbo.Students t2 
   4:      on t1.StudentID = t2.StudentID
   5:  inner join dbo.Subjects t3
   6:      on t1.SubjectID = t3.SubjectID

 

 

執行結果如下:

image

 

接著利用彙總函數MAX(下圖1)來取得每一科目(下圖2)最高得分。最後依據國文、英文、數學及物理等資料行順序(下圖3)來產生類似樞紐分析表的結果。

image

 

完整程式碼如下:

   1:  select p1.StudentName as 姓名,p1.國文,p1.英文,p1.數學,p1.物理
   2:  from 
   3:  (
   4:      select t2.Name as StudentName,t3.Name as SubjectName,t1.Score
   5:      from dbo.Scores t1
   6:      inner join dbo.Students t2 
   7:          on t1.StudentID = t2.StudentID
   8:      inner join dbo.Subjects t3
   9:          on t1.SubjectID = t3.SubjectID
  10:  ) as s1
  11:  pivot 
  12:  (
  13:      MAX(s1.Score)
  14:      for s1.SubjectName
  15:      IN ([國文],[英文],[數學],[物理])
  16:  ) as p1    

 

執行結果如下:

image

 

【參考資料】