==================================聲明==================================
本文原創,轉載在正文中顯要的注明作者和出處,並保證文章的完整性。
未經作者同意請勿修改(包括本聲明),保留法律追究的權利。
未經作者同意請勿用於學術性引用。
未經作者同意請勿用於商業出版、商業印刷、商業引用。
本文不定期修正完善,為保證內容正確,建議移步原文處閱讀。
本文鏈接:http://www.cnblogs.com/wlsandwho/p/4423956.html
=======================================================================
看了好長時間的資料,總算是看懂了點。(另外怎樣才能把右面的這個長毛的土豆去掉?----> 對,就是它!)
趕緊記錄下來。
=======================================================================
表格和數據。(和http://www.cnblogs.com/wlsandwho/p/4416222.html的相同)
1 USE tempdb 2 GO 3 -------------------------------------------------------------------------- 4 IF OBJECT_ID('Student','U') IS NOT NULL 5 DROP TABLE Student 6 GO 7 8 CREATE TABLE Student 9 ( 10 StuID NVARCHAR(8) PRIMARY KEY, 11 Name NVARCHAR(5), 12 EntranceTime DATETIME 13 ) 14 GO 15 16 INSERT INTO Student(StuID,Name,EntranceTime) VALUES('20080001','Lily','2008-08-27') 17 INSERT INTO Student(StuID,Name,EntranceTime) VALUES('20090002','Lucy','2009-08-26') 18 INSERT INTO Student(StuID,Name,EntranceTime) VALUES('20070003','Jack','2007-08-28') 19 GO 20 -------------------------------------------------------------------------- 21 IF OBJECT_ID('SltCourse','U') IS NOT NULL 22 DROP TABLE SltCourse 23 GO 24 25 CREATE TABLE SltCourse --SelectiveCourse 26 ( 27 ID INT PRIMARY KEY IDENTITY(1,1), 28 StuID NVARCHAR(8), 29 CourseName NVARCHAR(10), 30 Score INT 31 ) 32 GO 33 34 INSERT INTO SltCourse(StuID,CourseName,Score) VALUES('20070003','電腦維修',90) 35 INSERT INTO SltCourse(StuID,CourseName,Score) VALUES('20070003','剪紙',80) 36 INSERT INTO SltCourse(StuID,CourseName,Score) VALUES('20070003','市場策划',95) 37 INSERT INTO SltCourse(StuID,CourseName,Score) VALUES('20070003','信息檢索',100) 38 39 INSERT INTO SltCourse(StuID,CourseName,Score) VALUES('20080001','插花',99) 40 INSERT INTO SltCourse(StuID,CourseName,Score) VALUES('20080001','剪紙',96) 41 INSERT INTO SltCourse(StuID,CourseName,Score) VALUES('20080001','刺綉',92) 42 43 INSERT INTO SltCourse(StuID,CourseName,Score) VALUES('20090002','插花',98) 44 GO
查看一下
1 SELECT s.StuID,s.Name,s.EntranceTime,sc.CourseName,sc.Score FROM Student s,SltCourse sc WHERE s.stuid=sc.stuid 2 GO
=======================================================================
現在來看這個表格,前三列有很多數據是重復的,而且也不便於閱讀。之前使用了row_number函數,這里使用下別的——PIVOT來實現一個行轉列。
預期效果。
=======================================================================
靜態版。這需要預知要轉換成列名的數據。
1 WITH ReportCard 2 AS( 3 SELECT s.StuID,s.Name,s.EntranceTime,sc.CourseName,sc.Score FROM Student s,SltCourse sc WHERE s.stuid=sc.stuid 4 ) 5 SELECT * FROM ReportCard PIVOT(MAX(Score) FOR CourseName IN([電腦維修],[剪紙],[市場策划],[信息檢索],[插花],[刺綉]) ) AS T 6 GO
結果。
當在第三行加上篩選語句時,可以得到指定的某一行。例如:
1 WITH ReportCard 2 AS( 3 SELECT s.StuID,s.Name,s.EntranceTime,sc.CourseName,sc.Score FROM Student s,SltCourse sc WHERE s.stuid=sc.stuid AND s.StuID='20090002' 4 ) 5 SELECT * FROM ReportCard PIVOT(MAX(Score) FOR CourseName IN([電腦維修],[剪紙],[市場策划],[信息檢索],[插花],[刺綉]) ) AS T 6 GO
結果。
=======================================================================
動態版。先查詢出要轉為列的行數據,然后設置格式,再拼接字符串。
1 DECLARE @strCN NVARCHAR(100) 2 SELECT @strCN=ISNULL(@strCN+',','')+ QUOTENAME(CourseName) FROM SltCourse GROUP BY CourseName 3 --PRINT @DCN 4 5 DECLARE @SqlStr NVARCHAR(1000) 6 SET @SqlStr=' 7 WITH ReportCard 8 AS( 9 SELECT s.StuID,s.Name,s.EntranceTime,sc.CourseName,sc.Score FROM Student s,SltCourse sc WHERE s.stuid=sc.stuid 10 ) 11 SELECT * FROM ReportCard PIVOT(MAX(Score) FOR CourseName IN('+@strCN+') ) AS T' 12 EXEC(@sqlstr) 13 GO
=======================================================================
題外話,關於PIVOT中聚合函數的使用。
我剛用TSQL不久,行轉列都是匯總一些數值類型的數據,比方說,周一到周日的營業收入啦,數理化史地生成績啦之類的。
這些數值類型的,選擇聚合函數時,當然是需要什么選什么啦。
看例子。
1 USE tempdb 2 GO 3 4 IF OBJECT_ID('AggregateFuncTest1','U') IS NOT NULL 5 DROP TABLE AggregateFuncTest1 6 GO 7 8 CREATE TABLE AggregateFuncTest1 9 ( 10 ID INT IDENTITY(1,1) PRIMARY KEY, 11 DayOfWeek NVARCHAR(3), 12 Income INT 13 ) 14 GO 15 16 INSERT INTO AggregateFuncTest1(DayOfWeek,Income) VALUES('星期一',100) 17 INSERT INTO AggregateFuncTest1(DayOfWeek,Income) VALUES('星期二',200) 18 INSERT INTO AggregateFuncTest1(DayOfWeek,Income) VALUES('星期三',300) 19 INSERT INTO AggregateFuncTest1(DayOfWeek,Income) VALUES('星期四',400) 20 INSERT INTO AggregateFuncTest1(DayOfWeek,Income) VALUES('星期五',500) 21 INSERT INTO AggregateFuncTest1(DayOfWeek,Income) VALUES('星期六',600) 22 INSERT INTO AggregateFuncTest1(DayOfWeek,Income) VALUES('星期日',700) 23 GO 24 ---------------------------------------------------------------------- 25 SELECT DayOfWeek,Income FROM AggregateFuncTest1 26 GO 27 ---------------------------------------------------------------------- 28 WITH Rst AS 29 ( 30 SELECT DayOfWeek,Income FROM AggregateFuncTest1 31 ) 32 SELECT [星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日] FROM Rst 33 PIVOT(AVG(Income) FOR DayOfWeek IN ([星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日])) AS T 34 GO 35 ---------------------------------------------------------------------- 36 INSERT INTO AggregateFuncTest1(DayOfWeek,Income) VALUES('星期一',1000) 37 GO 38 39 WITH Rst AS 40 ( 41 SELECT DayOfWeek,Income FROM AggregateFuncTest1 42 ) 43 SELECT [星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日] FROM Rst 44 PIVOT(AVG(Income) FOR DayOfWeek IN ([星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日])) AS T 45 GO 46 ---------------------------------------------------------------------- 47 DROP TABLE AggregateFuncTest1
結果:
只要看一看、運行一下就會發現,聚合函數的選擇是根據需要來的。當我有2個星期一的入賬時,由AVG函數的來的結果是不同的。
那么,求最大就是用Max,最小用Min,求和就是Sum,等等等等。沒啥說的。
如果數據是字符類型呢?
再看例子。例如,辦公室值日表。
1 USE tempdb 2 GO 3 4 IF OBJECT_ID('AggregateFuncTest2','U') IS NOT NULL 5 DROP TABLE AggregateFuncTest2 6 GO 7 8 CREATE TABLE AggregateFuncTest2 9 ( 10 ID INT IDENTITY(1,1) PRIMARY KEY, 11 DayOfWeek NVARCHAR(3), 12 Name NVARCHAR(10) 13 ) 14 GO 15 16 INSERT INTO AggregateFuncTest2(DayOfWeek,Name) VALUES('星期一','Jack') 17 INSERT INTO AggregateFuncTest2(DayOfWeek,Name) VALUES('星期二','Lucy') 18 INSERT INTO AggregateFuncTest2(DayOfWeek,Name) VALUES('星期三','Lily') 19 INSERT INTO AggregateFuncTest2(DayOfWeek,Name) VALUES('星期四','Bob') 20 INSERT INTO AggregateFuncTest2(DayOfWeek,Name) VALUES('星期五','Angela') 21 INSERT INTO AggregateFuncTest2(DayOfWeek,Name) VALUES('星期六','Bella') 22 INSERT INTO AggregateFuncTest2(DayOfWeek,Name) VALUES('星期日','') 23 GO 24 ------------------------------------------------------------------------ 25 SELECT DayOfWeek,Name FROM AggregateFuncTest2 26 GO 27 28 WITH Rst AS 29 (SELECT DayOfWeek,Name FROM AggregateFuncTest2) 30 SELECT * FROM Rst PIVOT (MAX(Name) FOR DayOfWeek IN ([星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日]) ) AS PVT 31 ------------------------------------------------------------------------ 32 DROP TABLE AggregateFuncTest2
結果:
單個的數據可以用Max等函數來湊合使用,因為這些函數可以接受字符類型的參數。
但如果數據多了,不止一個的時候呢?例如,又來了一個同事,於是周六多了一個人,那就順便大掃除吧。
1 INSERT INTO AggregateFuncTest2(DayOfWeek,Name) VALUES('星期六','Alice') 2 GO 3 WITH Rst AS 4 (SELECT DayOfWeek,Name FROM AggregateFuncTest2) 5 SELECT * FROM Rst PIVOT (MAX(Name) FOR DayOfWeek IN ([星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日]) ) AS PVT 6 GO
結果:
Alice居然不用值日,這怎么行!怎能不給表現的機會?女漢子能頂一個天!
這種情況只能自己專門寫一個聚合函數來拼接字符串了。(當然可以先拼接好字符串,再行轉列。)
=======================================================================
用戶自定義聚合函數好復雜,不寫了。(其實是我還沒搞懂這些呢,C#無愛。)