1. 程式人生 > >Sql Server裡巧用Case將多行顯示的資料合併為一行顯示

Sql Server裡巧用Case將多行顯示的資料合併為一行顯示

轉載地址:http://www.cnblogs.com/kingthy/archive/2008/04/29/1175697.html

昨晚在CSDN論壇上看到有某個人問了類似這樣的一個問題,現有三個資料表,分別是學生表,課程表,成績表。它們的結構與樣例資料如下:

學生表:
學生Id    姓名
1             張三
2             李四
3             王五


課程表:
課程Id    課程名
1             語文
2             化學
3             外語
4             物理


成績表
學生Id     課程Id        成績
1               1                 60
1               2                 70
1               3                 65
1               4                 90
2               1                 80
2               2                 65
2               3                 85
2               4                 80
3               1                 50
3               2                 75
3               3                 85
3               4                 60

現要求在一行中輸出每個學生的所有課程的成績單,顯示樣例格式如下:
姓名        語文        化學       外語        物理
張三        60            70           65            90
李四        80            65           85            80
王五        50            75           85            60

當大家看到這樣的題目時會優先考慮到的是怎樣的一條SQL語句呢?巢狀Select?對,在將行轉換為列時,也許這種方法是最優先考慮到(或者你是高手,所以不是優先考慮到這個而是其它),所以我最開始也寫出了下面這條語句:

SELECT B.姓名,
(
SELECT 成績 FROM 成績表 INNERJOIN 課程 ON 成績表.課程ID=課程.課程ID WHERE 成績表.學生ID=B.學生ID AND 課程.課程名='語文' ) AS 語文,
(
SELECT 成績 FROM 成績表 INNERJOIN 課程 ON 成績表.課程ID=課程.課程ID WHERE 成績表.學生ID=B.學生ID AND 課程.課程名
='化學' ) AS 化學,
(
SELECT 成績 FROM 成績表 INNERJOIN 課程 ON 成績表.課程ID=課程.課程ID WHERE 成績表.學生ID=B.學生ID AND 課程.課程名='外語' ) AS 外語,
(
SELECT 成績 FROM 成績表 INNERJOIN 課程 ON 成績表.課程ID=課程.課程ID WHERE 成績表.學生ID=B.學生ID AND 課程.課程名='物理' ) AS 物理
FROM 學生 B

這樣我們的目的是達到了,但後來我又想了一下,因為我們要的資料其實都在成績表裡,只不過現有的是用行來存放,那我們怎麼將它轉換為列顯示呢?嗯,這也許就要搬出聚合函式加Case條件來處理了!最終的SQL語句如下:

SELECT 姓名,
MAX(CASE 課程名 WHEN'語文'THEN 成績 ELSE0ENDAS 語文,
MAX(CASE 課程名 WHEN'化學'THEN 成績 ELSE0ENDAS 化學,
MAX(CASE 課程名 WHEN'外語'THEN 成績 ELSE0ENDAS 外語,
MAX(CASE 課程名 WHEN'物理'THEN 成績 ELSE0ENDAS 物理
FROM (SELECT B.姓名,C.課程名,D.成績 FROM 成績表 D 
INNERJOIN 學生 B ON B.學生ID=D.學生ID 
INNERJOIN 課程 C ON C.課程ID=D.課程ID) AS TMP GROUPBY 姓名

執行後,也是可以得到正確的資料,下面給出測試程式碼,大家可以直接在SQL查詢分析器裡執行

CREATETABLE 學生 (學生ID INT, 姓名 VARCHAR(20))
CREATETABLE 課程 (課程ID INT, 課程名 VARCHAR(20))
CREATETABLE 成績表 (學生ID INT, 課程ID INT, 成績 INT)

INSERTINTO 學生
SELECT1,'張三'UNIONALL
SELECT2,'李四'UNIONALL
SELECT3,'王五'

INSERTINTO 課程
SELECT1,'語文'UNIONALL
SELECT2,'化學'UNIONALL
SELECT3,'外語'UNIONALL
SELECT4,'物理'

INSERTINTO 成績表
SELECT1,1,60UNIONALL
SELECT1,2,70UNIONALL
SELECT1,3,65UNIONALL
SELECT1,4,90UNIONALL
SELECT2,1,80UNIONALL
SELECT2,2,65UNIONALL
SELECT2,3,85UNIONALL
SELECT2,4,80UNIONALL
SELECT3,1,50UNIONALL
SELECT3,2,75UNIONALL
SELECT3,3,85UNIONALL
SELECT3,4,60

--方法一
SELECT B.姓名,
(
SELECT 成績 FROM 成績表 INNERJOIN 課程 ON 成績表.課程ID=課程.課程ID WHERE 成績表.學生ID=B.學生ID AND 課程.課程名='語文' ) AS 語文,
(
SELECT 成績 FROM 成績表 INNERJOIN 課程 ON 成績表.課程ID=課程.課程ID WHERE 成績表.學生ID=B.學生ID AND 課程.課程名='化學' ) AS 化學,
(
SELECT 成績 FROM 成績表 INNERJOIN 課程 ON 成績表.課程ID=課程.課程ID WHERE 成績表.學生ID=B.學生ID AND 課程.課程名='外語' ) AS 外語,
(
SELECT 成績 FROM 成績表 INNERJOIN 課程 ON 成績表.課程ID=課程.課程ID WHERE 成績表.學生ID=B.學生ID AND 課程.課程名='物理' ) AS 物理
FROM 學生 B

--方法二
SELECT 姓名,
MAX(CASE 課程名 WHEN'語文'THEN 成績 ELSE0ENDAS 語文,
MAX(CASE 課程名 WHEN'化學'THEN 成績 ELSE0ENDAS 化學,
MAX(CASE 課程名 WHEN'外語'THEN 成績 ELSE0ENDAS 外語,
MAX(CASE 課程名 WHEN'物理'THEN 成績 ELSE0ENDAS 物理
FROM (SELECT B.姓名,C.課程名,D.成績 FROM 成績表 D 
INNERJOIN 學生 B ON B.學生ID=D.學生ID 
INNERJOIN 課程 C ON C.課程ID=D.課程ID) AS TMP GROUPBY 姓名


DROPTABLE 學生
DROPTABLE 課程
DROPTABLE 成績表
PS:用巢狀SELECT與用聚合函式加Case兩者的效率如何,我沒有測試,各位有興趣的可測試一下