天天看點

MySQL 如何實作行轉列分級輸出?概述情景簡介處理後的結果(行轉列):處理後的結果(行轉列)分級輸出:幾種方法比較分析小結

好久沒寫SQL語句,今天看到問答中的一個問題,拿來研究一下。

學校裡面記錄成績,每個人的選課不一樣,而且以後會添加課程,是以不需要把所有課程當作列。資料表裡面資料如下圖,使用姓名+課程作為聯合主鍵(有些需求可能不需要聯合主鍵)。本文以MySQL為基礎,其他資料庫會有些許文法不同。

資料庫表資料:

MySQL 如何實作行轉列分級輸出?概述情景簡介處理後的結果(行轉列):處理後的結果(行轉列)分級輸出:幾種方法比較分析小結
MySQL 如何實作行轉列分級輸出?概述情景簡介處理後的結果(行轉列):處理後的結果(行轉列)分級輸出:幾種方法比較分析小結
MySQL 如何實作行轉列分級輸出?概述情景簡介處理後的結果(行轉列):處理後的結果(行轉列)分級輸出:幾種方法比較分析小結
MySQL 如何實作行轉列分級輸出?概述情景簡介處理後的結果(行轉列):處理後的結果(行轉列)分級輸出:幾種方法比較分析小結

方法一:

這裡可以使用Max,也可以使用Sum;

注意第二張圖,當有學生的某科成績缺失的時候,輸出結果為Null; 

可以在第一個Case中加入Else語句解決這個問題:

方法二:

方法三:

MySQL 如何實作行轉列分級輸出?概述情景簡介處理後的結果(行轉列):處理後的結果(行轉列)分級輸出:幾種方法比較分析小結
MySQL 如何實作行轉列分級輸出?概述情景簡介處理後的結果(行轉列):處理後的結果(行轉列)分級輸出:幾種方法比較分析小結

第一種使用了分組,對每個課程分别處理。

第二種方法使用了表連接配接。

第三種使用了存儲過程,實際上可以是第一種或第二種方法的動态化,先計算出所有課程的數量,然後對每個分組進行課程查詢。這種方法的一個最大的好處是當新增了一門課程時,SQL語句不需要重寫。

關于行轉列和列轉行

這個概念似乎容易弄混,有人把行轉列了解為列轉行,有人把列轉行了解為行轉列;

這裡做個定義:

行轉列:把表中特定列(如本文中的:CNAME)的資料去重後做為列名(如查詢結果行中的“JAVA,mysql”,處理後是做為列名輸出);

列轉行:可以說是行轉列的反轉,把表中特定列(如本文處理結果中的列名“JAVA,mysql”)做為每一行資料對應列“CNAME”的值;

關于效率

不知道有什麼好的生成模拟資料的方法或工具,麻煩小夥伴推薦一下,抽空我做一下對比;

還有其它更好的方法嗎?

本文使用的幾種方法應該都有優化的空間,特别是使用存儲過程的話會更加靈活,功能更強大;

本文的分級隻是給出一種思路,分級的方法如果學生的成績相差較小的話将失去意義;

如果小夥伴有更好的方法,還請不吝賜教,感激不盡!

有些需求可能不需要聯合主鍵

有些需求可能不需要聯合主鍵,因為一門課程可能允許學生考多次,取最好的一次成績,或者取多次的平均成績。