SQL Server 2008中增強的匯總技巧


SQL Server 2008中SQL應用系列--目錄索引

 

SQL Server 2008中對匯總有明顯的增強,有點像Oracle的語法了。請看下面五個例子:

假定場景如下:某幾位員工在不同時間參加了不同的項目,獲取了相應的收入,現在需要按各種分類進行統計。

基本表如下:

View Code
USE testDb2
GO

IF NOT OBJECT_ID('tb_Income') IS NULL
DROP TABLE [tb_Income]

/****** Object: Table [dbo].[tb_Income] Script Date: 2012/4/5 8:19:21 ******/

CREATE TABLE [dbo].[tb_Income](
[TeamID] int not null,
[PName] [Nvarchar](20) NOT NULL,
[CYear] Smallint NOT NULL,
[CMonth] TinyInt NOT NULL,
[CMoney] Decimal (10,2) Not Null

)

GO
INSERT [dbo].[tb_Income]
SELECT 1,'胡一刀',2011,2,5600
union ALL SELECT 1,'胡一刀',2011,1,5678
union ALL SELECT 1,'胡一刀',2011,3,6798
union ALL SELECT 2,'胡一刀',2011,4,7800
union ALL SELECT 2,'胡一刀',2011,5,8899
union ALL SELECT 3,'胡一刀',2012,8,8877

union ALL SELECT 1,'苗人鳳',2011,1,3455
union ALL SELECT 1,'苗人鳳',2011,2,4567
union ALL SELECT 2,'苗人鳳',2011,3,5676
union ALL SELECT 3,'苗人鳳',2011,4,5600
union ALL SELECT 2,'苗人鳳',2011,5,6788
union ALL SELECT 2,'苗人鳳',2012,6,5679
union ALL SELECT 2,'苗人鳳',2012,7,6785

union ALL SELECT 2,'張無忌',2011,2,5600
union ALL SELECT 2,'張無忌',2011,3,2345
union ALL SELECT 2,'張無忌',2011,5,12000
union ALL SELECT 3,'張無忌',2011,4,23456
union ALL SELECT 3,'張無忌',2011,6,4567
union ALL SELECT 1,'張無忌',2012,7,6789
union ALL SELECT 1,'張無忌',2012,8,9998

union ALL SELECT 3,'趙半山',2011,7,6798
union ALL SELECT 3,'趙半山',2011,10,10000
union ALL SELECT 3,'趙半山',2011,9,12021
union ALL SELECT 2,'趙半山',2012,11,8799
union ALL SELECT 1,'趙半山',2012,12,10002

union ALL SELECT 3,'令狐沖',2011,8,7896
union ALL SELECT 3,'令狐沖',2011,9,7890
union ALL SELECT 2,'令狐沖',2011,10,7799
union ALL SELECT 2,'令狐沖',2011,11,9988
union ALL SELECT 2,'令狐沖',2012,9,34567
union ALL SELECT 3,'令狐沖',2012,12,5609

GO

數據如下:

SELECT * FROM tb_Income

/*

TeamID PName CYear CMonth CMoney
1 胡一刀 2011 2 5600.00
1 胡一刀 2011 1 5678.00
1 胡一刀 2011 3 6798.00
2 胡一刀 2011 4 7800.00
2 胡一刀 2011 5 8899.00
3 胡一刀 2012 8 8877.00
1 苗人鳳 2011 1 3455.00
1 苗人鳳 2011 2 4567.00
2 苗人鳳 2011 3 5676.00
3 苗人鳳 2011 4 5600.00
2 苗人鳳 2011 5 6788.00
2 苗人鳳 2012 6 5679.00
2 苗人鳳 2012 7 6785.00
2 張無忌 2011 2 5600.00
2 張無忌 2011 3 2345.00
2 張無忌 2011 5 12000.00
3 張無忌 2011 4 23456.00
3 張無忌 2011 6 4567.00
1 張無忌 2012 7 6789.00
1 張無忌 2012 8 9998.00
3 趙半山 2011 7 6798.00
3 趙半山 2011 10 10000.00
3 趙半山 2011 9 12021.00
2 趙半山 2012 11 8799.00
1 趙半山 2012 12 10002.00
3 令狐沖 2011 8 7896.00
3 令狐沖 2011 9 7890.00
2 令狐沖 2011 10 7799.00
2 令狐沖 2011 11 9988.00
2 令狐沖 2012 9 34567.00
3 令狐沖 2012 12 5609.00
*/



一、使用CUBE匯總數據(http://msdn.microsoft.com/en-us/library/bb522495%28v=sql.105%29.aspx

小試牛刀,

/*********使用CUBE匯總數據***************/

/********* 3w@live.cn 邀月***************/
SELECT TeamID as 小組ID,
SUM(CMoney) 總收入
FROM tb_Income
GROUP BY CUBE (TeamID)
----ORDER BY TeamID desc



邀月工作室

改進查詢:

SELECT TeamID as 小組ID,PName as 姓名,
SUM(CMoney) 總收入
FROM tb_Income
GROUP BY CUBE (TeamID,PName)

 

邀月工作室

 

二、使用ROLLUP匯總數據(http://msdn.microsoft.com/en-us/library/bb522495%28v=sql.105%29.aspx

 

/*********使用ROLLUP匯總數據***************/

/********* 3w@live.cn 邀月***************/

SELECT TeamID as 小組ID,PName as 姓名,
SUM(CMoney) 總收入
FROM tb_Income
GROUP BY ROLLUP (TeamID,PName)

 

邀月工作室

 注意:使用Rollup與指定的聚合列的順序有關。

 

 

三、使用Grouping Sets創建自定義匯總數據(http://msdn.microsoft.com/en-us/library/bb522495%28v=sql.105%29.aspx

 除了Cube和Rollup,還有更加靈活強大的自定義集合匯總--Grouping Sets

/*********使用Grouping Sets創建自定義匯總數據***************/

/********* 3w@live.cn 邀月***************/

SELECT TeamID as 小組ID,PName as 姓名,CYear as 年份,----min(CMonth) as 月份,
SUM(CMoney) 總收入
FROM tb_Income
Where CMonth=2
GROUP BY grouping SETS ((TeamID),(TeamID,PName),(CYear,PName))

 

邀月工作室

四、使用Grouping標識匯總行(http://technet.microsoft.com/zh-cn/library/ms178544.aspx

 細心的朋友可能會注意到,如果Cube后有兩個以上的匯總列時,可能會有一些列是Null,那么這些Null值究竟本身就是Null,還是由於聚合產生的Null呢,此時,Grouping函數大顯身手的機會來了。

/*********使用Grouping標識匯總行***************/

/********* 3w@live.cn 邀月***************/
SELECT TeamID as 小組ID,CYear as 年份,
CASE WHEN grouping(TeamID)=0 AND grouping(CYear)=1 THEN '小組匯總'
WHEN grouping(TeamID)=1 AND grouping(CYear)=0 THEN '年份匯總'
WHEN grouping(TeamID)=1 AND grouping(CYear)=1 THEN '所有匯總'
else '正常行' END as 行類別,
SUM(CMoney) 總收入
FROM tb_Income
GROUP BY CUBE (TeamID,CYear)

 

結果:

邀月工作室

至此,如果還有美中不足的話,那就是分組還是有點凌亂,下面我們將隆重推出終極武器--Grouping_ID,它與Grouping類似,但提供更為精細的顆粒度,以確認分組級別,當然使用也更為復雜,請看下面的示例:

五、使用Grouping_ID標識分組級別(http://technet.microsoft.com/zh-cn/library/bb510624.aspx

為了更清楚地說明問題,我們需要修改一下表結構,增加一個字段--項目所在的地點(AreaID),如下:

/*************修改表結構***************************/

ALTER table tb_Income
add AreaID int null

GO

update tb_Income SET AreaID=TeamID+CMonth%5+CYear%2
GO

此時數據變成這樣:

SELECT * FROM tb_Income

/*
TeamID PName CYear CMonth CMoney AreaID
1 胡一刀 2011 2 5600.00 4
1 胡一刀 2011 1 5678.00 3
1 胡一刀 2011 3 6798.00 5
2 胡一刀 2011 4 7800.00 7
2 胡一刀 2011 5 8899.00 3
3 胡一刀 2012 8 8877.00 6
1 苗人鳳 2011 1 3455.00 3
1 苗人鳳 2011 2 4567.00 4
2 苗人鳳 2011 3 5676.00 6
3 苗人鳳 2011 4 5600.00 8
2 苗人鳳 2011 5 6788.00 3
2 苗人鳳 2012 6 5679.00 3
2 苗人鳳 2012 7 6785.00 4
2 張無忌 2011 2 5600.00 5
2 張無忌 2011 3 2345.00 6
2 張無忌 2011 5 12000.00 3
3 張無忌 2011 4 23456.00 8
3 張無忌 2011 6 4567.00 5
1 張無忌 2012 7 6789.00 3
1 張無忌 2012 8 9998.00 4
3 趙半山 2011 7 6798.00 6
3 趙半山 2011 10 10000.00 4
3 趙半山 2011 9 12021.00 8
2 趙半山 2012 11 8799.00 3
1 趙半山 2012 12 10002.00 3
3 令狐沖 2011 8 7896.00 7
3 令狐沖 2011 9 7890.00 8
2 令狐沖 2011 10 7799.00 3
2 令狐沖 2011 11 9988.00 4
2 令狐沖 2012 9 34567.00 6
3 令狐沖 2012 12 5609.00 5
*/

我們需要統計小組、地區、月份三個維度的匯總數據。

/*********使用Grouping_ID標識分組級別***************/

/********* 3w@live.cn 邀月***************/

SELECT TeamID as 小組ID,AreaID as 地點ID,CMonth as 月份,
SUM(CMoney) 總收入
FROM tb_Income
Where AreaID IN (3,5,6,7,8,9,2,4) AND CYear =2011 AND CMonth=2
GROUP BY CUBE (TeamID,AreaID,CMonth)
----ORDER BY TeamID,AreaID,CMonth

統計結果:

邀月工作室

我們注意到,由於維度從兩個變成三個,此時數據比較凌亂,即使排序也不能有效解決。幸好,我們有Grouping_ID。看下例:

SELECT TeamID as 小組ID,AreaID as 地點ID,CMonth as 月份,

CASE grouping_ID(TeamID,AreaID,CMonth)
WHEN 1 THEN '小組/地點匯總'
WHEN 2 THEN '小組/月份匯總'
WHEN 3 THEN '小組匯總'
WHEN 4 THEN '地點/月份匯總'
WHEN 5 THEN '地點匯總'
WHEN 6 THEN '月份匯總'
WHEN 7 THEN '所有匯總'
else '正常行' END as 行類別,

SUM(CMoney) 總收入
FROM tb_Income
Where AreaID IN (3,5,6,7,8,9,2,4) AND CYear =2011 AND CMonth=2
GROUP BY CUBE (TeamID,AreaID,CMonth)
----ORDER BY TeamID,AreaID,CMonth

注意:代碼中新增的部分,這里需要稍微解釋一下,Grouping_ID接受幾個輸入列,返回二進制列列表計算的整數值,你可以把這三個維度,看作是(0,1,1)、(0,1,0)這樣類似的二進制,而Grouping_ID負責將運算結果以整數形式返回。

效果:

邀月工作室

至此,Group By的匯總暫時告一段落,希望您不虛此行,有所斬獲!

 

小結:帶有Cube,Rollup,grouping Sets的Group By函數在統計與分析中有着廣泛的應用,相信它的高效簡捷,在特定的場合會令你愛不釋手!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM