前幾天,看到一個羣友用WITH ROLLUP運算符。因爲自個兒沒用過,看到概念及結果都雲裏霧裏的,因此忽然來了興趣對生成結果測了一番。函數
1、概念:測試
WITH CUBE:生成的結果集顯示了所選列中值的全部組合的聚合。spa
WITH ROLLUP:生成的結果集顯示了所選列中值的某一層次結構的聚合。3d
GROUPING:當行由 WITH CUBE或WITH ROLLUP運算符添加時,該函數將致使附加列的輸出值爲 1;當行不禁 CUBE 或 ROLLUP 運算符添加時,該函數將致使附加列的輸出值爲 0。僅在與包含 CUBE 或 ROLLUP 運算符的 GROUP BY 子句相關聯的選擇列表中才容許分組。code
2、測試:blog
一、創建臨時表排序
CREATE TABLE #T0 ( [GRADE] [VARCHAR](50) NULL, --年級 [CLASS] [VARCHAR](50) NULL, --班級 [NAME] [VARCHAR](50) NULL, --姓名 [COURSE] [VARCHAR](50) NULL, --學科 [RESULT] [NUMERIC](8,2) NULL --成績 ) CREATE TABLE #T1 ( [ID] [INT] IDENTITY(1,1) NOT NULL, --序號 [GRADE] [VARCHAR](50) NULL, --年級 [CLASS] [VARCHAR](50) NULL, --班級 [NAME] [VARCHAR](50) NULL, --姓名 [COURSE] [VARCHAR](50) NULL, --學科 [RESULT] [NUMERIC](8,2) NULL --成績 ) CREATE TABLE #T2 ( [ID] [INT] IDENTITY(1,1) NOT NULL, --序號 [GRADE] [VARCHAR](50) NULL, --年級 [CLASS] [VARCHAR](50) NULL, --班級 [NAME] [VARCHAR](50) NULL, --姓名 [COURSE] [VARCHAR](50) NULL, --學科 [RESULT] [NUMERIC](8,2) NULL --成績 )
二、插入測試數據class
INSERT INTO #T0 (GRADE,CLASS,NAME,COURSE,RESULT) SELECT '2019','CLASS1','9A01','C#',100 UNION SELECT '2019','CLASS1','9A02','C#',100 UNION SELECT '2019','CLASS2','9B01','C#',100 UNION SELECT '2019','CLASS2','9B02','C#',100 UNION SELECT '2018','CLASS1','8A01','JAVA',100 UNION SELECT '2018','CLASS1','8A02','JAVA',100 UNION SELECT '2018','CLASS2','8B01','JAVA',100 UNION SELECT '2018','CLASS2','8B02','JAVA',100
查詢T0表結果:原理
三、GROUP BYim
拋磚引玉,看看經常使用的GROUP BY排序:默認以SELECT字段順序(GRADE->CLASS->NAME->COURSE)進行排序,如下兩種查詢結果是同樣的。
SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT FROM #T0 GROUP BY GRADE,CLASS,NAME,COURSE SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT FROM #T0 GROUP BY GRADE,CLASS,NAME,COURSE ORDER BY GRADE,CLASS,NAME,COURSE
四、WITH CUBE
原理1:以GROUP BY字段依次賦以NULL值進行分組聚合。
原理2:第1個字段(即GRADE字段)生成結果:除原始數據外,以第1個字段固定賦以NULL值,而後其它字段依次賦以NULL值進行分組聚合,結果由右往左進行排序。
下面開始測第1個字段的結果是怎麼來的:
INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT) SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT FROM #T0 GROUP BY GRADE,CLASS,NAME,COURSE INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT) SELECT 'ZZ' GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT FROM #T0 GROUP BY CLASS,NAME,COURSE INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT) SELECT 'ZZ' GRADE,'ZZ' CLASS,NAME,COURSE,SUM(RESULT) RESULT FROM #T0 GROUP BY NAME,COURSE INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT) SELECT 'ZZ' GRADE,'ZZ' CLASS,'ZZ' NAME,COURSE,SUM(RESULT) RESULT FROM #T0 GROUP BY COURSE INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT) SELECT 'ZZ' GRADE,'ZZ' CLASS,'ZZ' NAME,'ZZ' COURSE,SUM(RESULT) RESULT FROM #T0 --第1個字段結果排序由右往左 INSERT INTO #T2 (GRADE,CLASS,NAME,COURSE,RESULT) SELECT GRADE,CLASS,NAME,COURSE,RESULT FROM #T1 WHERE ID BETWEEN 1 AND 27 ORDER BY COURSE,NAME,CLASS,GRADE UPDATE #T2 SET GRADE=NULL WHERE GRADE='ZZ' UPDATE #T2 SET CLASS=NULL WHERE CLASS='ZZ' UPDATE #T2 SET NAME=NULL WHERE NAME='ZZ' UPDATE #T2 SET COURSE=NULL WHERE COURSE='ZZ'
WITH CUBE的結果:
SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT FROM #T0 GROUP BY GRADE,CLASS,NAME,COURSE WITH CUBE
自已測試的結果:
SELECT * FROM #T2
結果與上面一致。
其它字段優先跟哪一個字段組合、最終怎樣排序?呃,測過,沒搞清楚……
五、WITH ROLLUP
原理1:除原始數據外,以GROUP BY最後1個字段(即COURSE字段)固定賦以NULL值,而後其它字段依次賦以NULL值進行分組聚合,結果由左往右進行排序。
這個跟WITH CUBE的第1個字段很是相象:一個是第1個字段,一個是最後1個字段;一個結果是由右往左排序,一個結果是由左往右排序。
下面開始測結果是怎麼來的:
TRUNCATE TABLE #T1 TRUNCATE TABLE #T2 INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT) SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT FROM #T0 GROUP BY GRADE,CLASS,NAME,COURSE INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT) SELECT GRADE,CLASS,NAME,'ZZ' COURSE,SUM(RESULT) RESULT FROM #T0 WHERE NOT EXISTS (SELECT 1 FROM #T1 WHERE GRADE=#T0.GRADE AND CLASS=#T0.GRADE AND NAME=#T0.NAME AND COURSE='ZZ') GROUP BY GRADE,CLASS,NAME INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT) SELECT GRADE,CLASS,'ZZ' NAME,'ZZ' COURSE,SUM(RESULT) RESULT FROM #T0 WHERE NOT EXISTS (SELECT 1 FROM #T1 WHERE GRADE=#T0.GRADE AND CLASS=#T0.CLASS AND NAME='ZZ' AND COURSE='ZZ') GROUP BY GRADE,CLASS INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT) SELECT GRADE,'ZZ' CLASS,'ZZ' NAME,'ZZ' COURSE,SUM(RESULT) RESULT FROM #T0 WHERE NOT EXISTS (SELECT 1 FROM #T1 WHERE GRADE=#T0.GRADE AND CLASS='ZZ' AND NAME='ZZ' AND COURSE='ZZ') GROUP BY GRADE INSERT INTO #T1 (GRADE,CLASS,NAME,COURSE,RESULT) SELECT 'ZZ' GRADE,'ZZ' CLASS,'ZZ' NAME,'ZZ' COURSE,SUM(RESULT) RESULT FROM #T0 --結果排序由左往右 INSERT INTO #T2 (GRADE,CLASS,NAME,COURSE,RESULT) SELECT GRADE,CLASS,NAME,COURSE,RESULT FROM #T1 ORDER BY GRADE,CLASS,NAME,COURSE UPDATE #T2 SET GRADE=NULL WHERE GRADE='ZZ' UPDATE #T2 SET CLASS=NULL WHERE CLASS='ZZ' UPDATE #T2 SET NAME=NULL WHERE NAME='ZZ' UPDATE #T2 SET COURSE=NULL WHERE COURSE='ZZ'
WITH ROLLUP的結果:
SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT FROM #T0 GROUP BY GRADE,CLASS,NAME,COURSE WITH ROLLUP
本身測試的結果:
SELECT * FROM #T2
結果與上面一致。
六、GROUPING
這個就比較容易理解了,WITH CUBE與WITH ROLLUP用法同樣,先看結果:
SELECT GRADE,CLASS,NAME,COURSE,SUM(RESULT) RESULT,GROUPING(COURSE) [GROUPING] FROM #T0 GROUP BY GRADE,CLASS,NAME,COURSE WITH ROLLUP
上面GROUPING的是COURSE字段,有NULL值就是WITH ROLLUP額外添加的,GROUPING結果值爲1。
有了GROUPING,那作小計、總計就方便了。
SELECT GRADE, CASE WHEN GROUPING(GRADE)=1 AND GROUPING(CLASS)=1 THEN '總計' WHEN GROUPING(GRADE)=0 AND GROUPING(CLASS)=1 THEN '小計' ELSE CLASS END CLASS, NAME,COURSE,SUM(RESULT) RESULT FROM #T0 GROUP BY GRADE,CLASS,NAME,COURSE WITH ROLLUP
好了,原理測試及應用就到這裏結束了。