SQLSERVER中的ALL、PERCENT、CUBE關鍵字、ROLLUP關鍵字和GROUPING函數


SQLSERVER中的ALL、PERCENT、CUBE關鍵字、ROLLUP關鍵字和GROUPING函數

 先來創建一個測試表

 1 USE [tempdb]
 2 GO
 3 
 4 CREATE TABLE #temptb(id INT ,NAME VARCHAR(200))
 5 GO
 6 
 7 INSERT INTO [#temptb] ( [id], [NAME] )
 8 SELECT 1,'中國' UNION ALL
 9 SELECT 2,'中國' UNION ALL
10 SELECT 3,'英國' UNION ALL
11 SELECT 4,'英國' UNION ALL
12 SELECT 5,'美國' UNION ALL
13 SELECT 6,'美國' UNION ALL
14 SELECT null, '法國' UNION ALL
15 SELECT 8,'法國' 
16 GO
17 
18 SELECT * FROM [#temptb]
19 GO

 

先來看一下SELECT語句的語法:

1 SELECT [ ALL | DISTINCT ] [ topSubclause ] aliasedExpr 
2       [{ , aliasedExpr }] FROM fromClause [ WHERE whereClause ] [ GROUP BY groupByClause [ HAVING havingClause ] ] [ ORDER BY orderByClause ]
3 or
4 SELECT VALUE [ ALL | DISTINCT ] [ topSubclause ] expr FROM fromClause [ WHERE whereClause ] [ GROUP BY groupByClause [ HAVING havingClause ] ] [ ORDER BY orderByClause

 

ALL關鍵字:指定在結果集中可以顯示重復的行,這是默認的關鍵字,也就是說,當您在查詢中不使用ALL關鍵字,默認都已經附加上了ALL這個關鍵字

例如下面兩個SQL語句,實際上是等價的,都會把重復的記錄select出來

1 --這兩個語句是等價的
2 SELECT * FROM [#temptb]
3 GO
4 -------------------------------------------
5 SELECT ALL * FROM [#temptb]
6 GO

如果您需要把唯一值select出來,過濾掉那些重復值需要使用DISTINCT關鍵字

1 SELECT DISTINCT([NAME]) FROM [#temptb]

而當您把SQL語句,字段放在ALL括號中,這時候就會變成一個表達式,例如下面SQL語句

1 SELECT ALL([NAME]+'您好') AS '國別' FROM [#temptb]

在我上一篇文章里:處理表重復記錄(查詢和刪除)

在Name相同ID最大的記錄,其中有一個SQL語句

1 SELECT  *
2 FROM    [#temptb] a
3 WHERE   ID!<ALL ( SELECT    ID
4                   FROM      [#temptb]
5                   WHERE     Name = a.Name )

如果去掉ALL關鍵字會怎樣呢?

因為子查詢需要的是一個表達式,所以需要使用ALL關鍵字把他變為一個表達式,所以要用ALL

 

ALL關鍵字還可以放在GROUP BY 之后

這里要分兩種情況,一種是SQL語句中有where子句的的,另一種是SQL語句中沒有where子句的

情況一:

1 SELECT AVG(id) FROM [#temptb] WHERE NAME='法國' GROUP BY ALL NAME
2 SELECT AVG(id) FROM [#temptb] WHERE NAME='法國'  GROUP BY NAME

對於沒有符合條件的行的組,這里是沒有符合name='法國',作為聚合值的列值為NULL

如果沒有ALL關鍵字,GROUP BY子句將不顯示沒有符合條件的行的組

情況二:

1 SELECT AVG(id) FROM [#temptb]  GROUP BY ALL NAME
2 SELECT AVG(id) FROM [#temptb]  GROUP BY  NAME

當SQL語句中沒有where子句的時候,查詢出來的結果都是一樣的

 

ALL關鍵字還可以放在UNION之后

1 USE [GPOSDB]
2 GO
3 INSERT INTO [dbo].[SystemPara] ( [ParaValue], [Name], [Description] )
4 SELECT 'nihao','nihao','nihao' UNION ALL
5 SELECT 'nihao','nihao','nihao' 

 


PERCENT關鍵字

PERCENT關鍵字需要跟TOP 關鍵字一起使用

從結果集中輸出百分之N行,n必須是介於0~100之間的整數

1 SELECT TOP 10 PERCENT * from [#temptb]
2 GO


上面的SQL語句意思是:從[#temptb]表中輸出10%的記錄數,因為沒有使用order by子句,所以這條記錄是隨機的

因為[#temptb]表有8條記錄,8*10%=0.8 四舍五入之后相當於一條記錄

1 SELECT TOP 30 PERCENT * from [#temptb]
2 GO

8*30%=2.4 四舍五入之后相當於三條記錄,SQLSERVER在這里就算四舍五入不足三條記錄,他也會輸出偏大的數,也就是三條記錄

 


CUBE關鍵字

CUBE關鍵字:如果需要在結果集內不僅包含由GROUP BY提供的正常行,還包含匯總行,可以用CUBE關鍵字。CUBE關鍵字與GROUP BY一起使用

當使用CUBE關鍵字的時候,可以使用GROUPING函數來輸出一個額外的列,當結果行是正常的行時,返回0;當結果行是匯總行時,返回1。

1 SELECT  AVG(id) AS '平均值', GROUPING(NAME) AS '是否已匯總'
2 FROM    [#temptb]
3 GROUP BY NAME
4         WITH CUBE

最后一行顯示了GROUP BY的記錄有多少行,一共有4行記錄,而在匯總行(即最后一行)是否已匯總那列顯示1,表示是匯總行


Grouping關鍵字

指示是否聚合 GROUP BY 列表中的指定列表達式。

在結果集中,如果 GROUPING 返回 1 則指示聚合;返回 0 則指示不聚合。

如果指定了 GROUP BY,則 GROUPING 只能用在 SELECT <select> 列表、HAVING 和 ORDER BY 子句中。

http://msdn.microsoft.com/zh-cn/library/ms178544(v=sql.105).aspx

GROUPING 用於區分標准空值和由 ROLLUP、CUBE 或 GROUPING SETS 返回的空值。

作為 ROLLUP、CUBE 或 GROUPING SETS 操作結果返回的 NULL 是 NULL 的特殊應用。

它在結果集內作為列的占位符,表示全體。

 

以下示例將分組 SalesQuota 並聚合 SaleYTD 數量。GROUPING 函數應用於 SalesQuota 列。

1 USE [AdventureWorks];
2 GO
3 SELECT  SalesQuota, SUM(SalesYTD) 'TotalSalesYTD',
4         GROUPING(SalesQuota) AS 'Grouping'
5 FROM    Sales.SalesPerson
6 GROUP BY SalesQuota
7         WITH ROLLUP;
8 GO

結果集在 SalesQuota 下面顯示兩個空值。

第一個 NULL 代表從表中的這一列得到的空值組。

第二個 NULL 位於 ROLLUP 操作所添加的匯總行之中。

匯總行顯示所有 SalesQuota 組的 TotalSalesYTD 數量,並以 Grouping 列中的 1 進行指示。

 


 

http://msdn.microsoft.com/zh-cn/library/ms191500(v=sql.100).aspx
對簡單匯總報表使用 Transact-SQL

生成簡單匯總報表的應用程序可使用下列 Transact-SQL 元素:

ROLLUP、CUBE 或 GROUPING SETS 運算符。這些是 SELECT 語句的 GROUP BY 子句的擴展。

COMPUTE 或 COMPUTE BY 運算符。這兩種運算符也與 GROUP BY 相關聯。

這些運算符生成的結果集中,既包含每個項目的明細行,也包含每個組的匯總行,匯總行顯示了該組的聚合合計。

GROUP BY 子句可用於生成只包含各組的聚合而不包含其明細行的結果。

應用程序應使用 Analysis Services,而不是 CUBE、ROLLUP、COMPUTE 或 COMPUTE BY。

特別要注意的是,CUBE 和 ROLLUP 應當只用在無法訪問 OLE DB 或 ADO 的環境中,例如腳本或存儲過程中。

支持 COMPUTE 和 COMPUTE BY 是為了向后兼容。

應當優先選用 ROLLUP 運算符而非 COMPUTE 或 COMPUTE BY。由 COMPUTE 或 COMPUTE BY 生成的匯總值將作為多個單獨的結果集返回,

這些結果集之間還插入了包含各組明細行的結果集;或者作為包含合計的結果集返回,附加在主結果集之后。

處理這些多個結果集將增加應用程序代碼的復雜性。服務器游標既不支持 COMPUTE,也不支持 COMPUTE BY。

但 ROLLUP 支持服務器游標。CUBE 和 ROLLUP 將生成單個結果集,其中包含嵌入的小計合計行。

此外,查詢優化器有時還可以為 ROLLUP 生成比為 COMPUTE 和 COMPUTE BY 生成的執行計划更高效的執行計划。

如果使用不帶這些運算符的 GROUP BY,將返回單個結果集,其中每組對應一行,行中包含該組的聚合小計。結果集中沒有明細行。

 


SQLSERVER中CubeRollUp的用法

CubeRollUp可以對查詢的數據進行匯總,在數據統計中經常用到,尤其是做報表時,用在Select語句中

下面就對兩種統計方式進行對比

SQL腳本如下:

 1 USE [tempdb]
 2 GO
 3 CREATE TABLE t_test
 4 (
 5   id INT ,
 6   productName VARCHAR(200) ,
 7   price MONEY ,
 8   num INT ,
 9   amount INT ,
10   operatedate DATETIME
11 )
12 GO
13 
14 --插入隨機數據
15 DECLARE @i INT 
16 DECLARE @rand MONEY
17 DECLARE @date DATETIME
18 DECLARE @index INT 
19 DECLARE @DateBase INT 
20 SET @date = '2012-10-23'
21 SET @i = 1
22 WHILE ( @i < 18 ) 
23     BEGIN
24         SET @rand = RAND() * 20
25         SET @index = CAST(RAND() * 3 AS INT)
26         SET @DateBase = CAST(RAND() * 10 AS INT)
27  
28         INSERT  INTO t_test ( id, productName, price, num, amount, operatedate )
29         VALUES  ( @i, 'product' + CAST (@index AS VARCHAR(10)), @rand, 100,
30                   @rand * 100, @date + @DateBase )
31         SET @i = @i + 1
32     END
33  
34  
35 SELECT  *  FROM    t_test

 

 分別用兩種方式統計:

 1 --分別用兩種方式統計:
 2  
 3 SELECT  CASE WHEN GROUPING(operatedate) = 1 THEN '小計'
 4              ELSE CONVERT(VARCHAR(10), operatedate, 120)
 5         END AS 日期, CASE WHEN GROUPING(productName) = 1 THEN '小計'
 6                         ELSE productName
 7                    END AS 產品名稱, SUM(amount) / SUM(num) AS 平均價格, SUM(num) AS 數量,
 8         SUM(amount) AS 金額
 9 FROM    t_test
10 GROUP BY operatedate, productName  WITH ROLLUP;   
11 -------------------------------------------------------------------
12 SELECT  CASE WHEN GROUPING(operatedate) = 1 THEN '小計'
13              ELSE CONVERT(VARCHAR(10), operatedate, 120)
14         END AS 日期, CASE WHEN GROUPING(productName) = 1 THEN '小計'
15                         ELSE productName
16                    END AS 產品名稱, SUM(amount) / SUM(num) AS 平均價格, SUM(num) AS 數量,
17         SUM(amount) AS 金額
18 FROM    t_test
19 GROUP BY operatedate, productName WITH CUBE; 

ROLLUP 按照分組順序,先對第一個字段operatedate分組,在組內進行統計,最后給出合計

1 SELECT  CASE WHEN GROUPING(operatedate) = 1 THEN '小計'  --用GROUPING得出是否是匯總行,這個例子里最后一行是匯總行
2              ELSE CONVERT(VARCHAR(10), operatedate, 120)
3         END AS 日期, CASE WHEN GROUPING(productName) = 1 THEN '小計'
4                         ELSE productName
5                    END AS 產品名稱, SUM(amount) / SUM(num) AS 平均價格, SUM(num) AS 數量,
6         SUM(amount) AS 金額
7 FROM    t_test
8 GROUP BY operatedate, productName  WITH ROLLUP;   --因為operatedate和productName字段都在GROUPING函數里統計是否匯總,所以GROUP BY后面就需要加operatedate和productName這兩個字段

 

CUBE 會對所有的分組字段進行統計,如上例,先對日期求小計,也就是統計每天的產品總金額,然后統計每個產品的總金額,最后給出總的合計。

ROLLUPCUBE的區別就是: ROLLUP 只會去統計group by 后面的第一個字段每個分組的小計和第一個字段的總計
 
Grouping(字段名) 用來區分當前行是不是小計產生的行,  Grouping(字段名)=1 說明是統計行,Grouping(字段名)=0 說明是表中行

可以用在case,where 后面

http://www.2cto.com/database/201210/163455.html


另外一個例子

SQL腳本如下:

 1 USE [tempdb]
 2 GO
 3 CREATE TABLE Sales (EmpId INT, Yr INT, Sales MONEY)
 4 INSERT Sales VALUES(1, 2005, 12000)
 5 INSERT Sales VALUES(1, 2006, 18000)
 6 INSERT Sales VALUES(1, 2007, 25000)
 7 INSERT Sales VALUES(2, 2005, 15000)
 8 INSERT Sales VALUES(2, 2006, 6000)
 9 INSERT Sales VALUES(3, 2006, 20000)
10 INSERT Sales VALUES(3, 2007, 24000)
11 
12 SELECT * FROM [dbo].[Sales]
View Code

ROLLUP

1 SELECT EmpId, Yr, SUM(Sales) AS Sales
2 FROM Sales
3 GROUP BY EmpId, Yr WITH ROLLUP

CUBE

1 SELECT EmpId, Yr, SUM(Sales) AS Sales
2 FROM Sales
3 GROUP BY EmpId, Yr WITH CUBE

CUBE比ROLLUP多了年份的統計,統計了2005、2006、2007年的銷售額

可以用下圖來表示

ROLLUP

 

CUBE

 http://blogs.msdn.com/b/craigfr/archive/2007/10/11/grouping-sets-in-sql-server-2008.aspx

 


驗證CUBE和ROLLUP 的區別

ROLLUPCUBE的區別就是: ROLLUP 只會去統計group by 后面的第一個字段每個分組的小計和第一個字段的總計

我們修改一下上面那個實驗

 1 USE [tempdb]
 2 GO
 3 CREATE TABLE Sales (EmpId INT,productName VARCHAR(200), Yr INT, Sales MONEY)
 4 GO
 5 INSERT Sales VALUES(1,'product2', 2005, 12000)
 6 INSERT Sales VALUES(1,'product1', 2005, 18000)
 7 INSERT Sales VALUES(1,'product0', 2006, 25000)
 8 INSERT Sales VALUES(1,'product2', 2007, 15000)
 9 INSERT Sales VALUES(2,'product1', 2005, 60000)
10 INSERT Sales VALUES(2,'product1', 2006, 22000)
11 INSERT Sales VALUES(2,'product0', 2007, 24000)
12 INSERT Sales VALUES(3,'product0', 2005, 32000)
13 INSERT Sales VALUES(3,'product2', 2006, 42000)
14 INSERT Sales VALUES(3,'product0', 2007, 24000)
15 GO
16 
17 SELECT * FROM [dbo].[Sales]
View Code

 ROLLUP

1 SELECT EmpId, Yr,[productName], SUM(Sales) AS Sales
2 FROM Sales
3 GROUP BY EmpId, Yr,[productName] WITH ROLLUP

CUBE

1 SELECT EmpId, Yr,[productName], SUM(Sales) AS Sales
2 FROM Sales
3 GROUP BY EmpId, Yr,[productName] WITH CUBE

可以看到CUBE除了統計EmpId字段之外,還統計了GROUP BY后面的Yr和productName這兩個字段

而ROLLUP只統計了EmpId這個字段


 

總結

這些關鍵字和函數對平時用於統計的應用程序都非常有用,如果大家對這些函數功能都很熟悉的話,在開發當中一定能夠得心應手

另外,個人覺得PERCENT關鍵字可以應用在分頁上

 

如有不對的地方,歡迎大家拍磚哦o(∩_∩)o

本文版權歸作者所有,未經作者同意不得轉載。


免責聲明!

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



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