行列轉換

自從看《學技術的不能自廢武功》這篇文章後,我深有感觸,於是對自己以前學過的知識又重新溫習了一次,結果終於發現了一些新的感悟,現將其感悟發表,於大家共勉:

關於 sql 行轉列的感悟
(1)
要將其轉變爲:
 
 
(2)
可以看得出來,表2列是由表1的行數據轉化而來的,只有姓名列是表1中的列。
一步一步的來嘛,其他的列難搞,如果表2只有1列姓名的話,那麼very easy了,不就是一個簡單的分組嘛。
Select 姓名 From 1 Group By 姓名
 
現在sql語句的架子搭起來了,無論以後如何變化,分組是少不了的。
那麼開始下一步,想這個結果集中再添加1列,多了我們不加,因爲你不論是能處理語文,還是數學,還是英語列,那麼其他的列只要原樣照抄就可以了,頂多修改一下參數而已。
從語文列開始吧,這一列的數據都可以從表1中找到,如果我們只要“語文”這一列,那麼也好寫。
Sql語句疑似:
Select 姓名,case  when 科目='語文' then 成績 end From 成績表 Group By 姓名
那就F5吧。
嗯,啊,...掛了。
趕緊看錯誤提示:
服務器: 消息 8120,級別 16,狀態 1,行 1
'成績表.成績' 在選擇列表中無效,因爲該列既不包含在聚合函數中,也不包含在 GROUP BY 子句中。

服務器: 消息 8120,級別 16,狀態 1,行 1
'成績表.科目' 在選擇列表中無效,因爲該列既不包含在聚合函數中,也不包含在 GROUP BY 子句中。
從錯誤信息中,可知字段成績和科目還必須在聚合函數中或Group By中,如何在Group By中呢?
 
數據倒是有了,可是行多了點,看來只能從聚合入手了。
到底是那個聚合?聚合有max,min,avg,sum,countmaxmin首先幹掉,我們不是要最大值,最小值,難道是平均值?難道是個數?難道是求和???
那就試試唄。
Select 姓名,sum(case when 科目='語文' then 成績 end) From 1 Group By 姓名
 
 
嘿,真不錯。
 
該有的都有了,就是沒列名,好辦,給個別名嘛。
Select 姓名,sum(case when 科目='語文' then 成績 end) As '語文' From1 Group By 姓名
 
那麼其他幾列也就好辦了。
 Select 姓名,
 sum(case when
科目='語文' then 成績 end) As '語文
' ,
 sum(case when 科目
='數學' then 成績 end) As '數學
',
 sum(case when 科目
='英語' then 成績 end) As '英語
'
 From 
表1 Group By 姓名
 
 
 可是結果有NULL,那還不好辦,你的case when then end沒寫完,還有else沒寫呢!
Select
姓名,
 sum(case when 科
='語文' then 成績 else 0 end) As '語文
' ,
 sum(case when 科目
='數學' then 成績 else 0 end) As '數學
',
 sum(case when 科目
='英語' then 成績 else 0 end) As '英語
'
 From
表1 Group By 姓名
 
 
 
終於修成正果了。
 
真的?
當然是假的?
怎麼假?
這不廢話麼!你現在寫的Sql語句只能支持科目表中只有語文數學英語,那萬一課程中加了一個叫物理的,那你不得改程序了嗎?!
怎麼辦?涼拌。
也就是說這個Sql語句中有變化的地方在紅字部分:
Select 姓名,
 sum(case when
科目='語文' then 成績 else 0 end) As '語文
' ,
 sum(case when
科目='數學' then 成績 else 0 end) As '數學
',
 sum(case when
科目='英語' then 成績 else 0 end) As '英語
'
 From  表1 Group By 姓名
紅字部分要從哪裏來?如果專心看,那麼應該能從中間看出來,哪些個“As '語文'”,哪些個“科目='語文'”,其實是數據表中的值,如果僅僅要查詢“語文,數學,英語”的話,那麼easy啊。
Select 課程 From 表1 Group By 科目
可是我們要的結果是:
sum(case when 科目='語文' then 成績 else 0 end) As '語文' ,
 sum(case when
科目='數學' then 成績 else 0 end) As '數學
',
 sum(case when
科目='英語' then 成績 else 0 end) As '英語
'
……………..

那不簡單,就是些字符串嘛。
Select ',sum(case when 科目='''+trim(科目)+ ''' then 成績 else 0 end) As '''+科目+'''' From 1 Group By 課程
結果爲:
 ,sum(case when 科目='語文' then 成績 else 0 end) As '語文' ,
 ,sum(case when
科目='數學' then 成績 else 0 end) As '數學',
 ,sum(case when
科目='英語' then 成績 else 0 end) As '英語'
 
 
 
哈哈,只要將這一段和剛纔的Select 姓名拼在一起就可以了。
現在麻煩來了,拼沒有問題。
declare @sql nvarchar(4000)
set @sql='Select 姓名 '
Select @sql=@sql+',sum(case when 科目='''+科目+ ''' then 成績 else 0 end) As '''+科目+''''
        From1 Group By 科目
Print @sql
這一段的結果是:
Select 姓名 ,sum(case when 科目='數學' then 成績 else 0 end) As '數學',sum(case when 科目='英語' then 成績 else 0 end) As '英語',sum(case when 科目='語文' then 成績 else 0 end) As '語文'
跟我們的要求比較接近了,還要附加一點東西:
Select 姓名 ,sum(case when 科目='數學' then 成績 else 0 end) As '數學',sum(case when 科目='英語' then 成績 else 0 end) As '英語',sum(case when 科目='語文' then 成績 else 0 end) As '語文' From 1 Group By 姓名
現在麻煩的是,如何執行這個字符串,現在我們將sql語句放在了 @sql 這個變量中了,怎麼執行?
靈機1動!
SqlServer中有個專門將字符串作爲sql語句執行的存儲過程---- sp_executesql
就是它了。
最終版本:
declare @sql nvarchar(4000)
set @sql='Select 姓名 '
Select @sql=@sql+',sum(case when 科目='''+科目+ ''' then 成績 else 0 end) As '''+科目+''''
        From 成績表 Group By 科目
Print @sql
set @sql=@sql+' From 成績表 Group By 姓名'
Print @sql
execute sp_executesql @sql
當然科目信息,不一定會從成績表中獲取,很有可能是一個專門的表格,比如叫“科目表”,那麼就更easy了。
declare @sql nvarchar(4000)
set @sql='Select 姓名 '
Select @sql=@sql+',sum(case when 科目='''+科目+ ''' then 成績 else 0 end) As '''+科目+''''
        From 科目表
Print @sql
set @sql=@sql+' From 1 Group By 姓名'
Print @sql
execute sp_executesql @sql
功德圓滿。

本文出自 “摩羯阿印” 博客,請務必保留此出處http://mikoo.blog.51cto.com/627637/124516

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章