GROUP BY中的WITH CUBE、WITH ROLLUP原理測試及GROUPING應用

来源:https://www.cnblogs.com/atomy/archive/2019/11/05/11795921.html
-Advertisement-
Play Games

前幾天,看到一個群友用WITH ROLLUP運算符。由於自個兒沒用過,看到概念及結果都雲里霧裡的,所以突然來了興趣對生成結果測了一番。 一、概念: WITH CUBE:生成的結果集顯示了所選列中值的所有組合的聚合。 WITH ROLLUP:生成的結果集顯示了所選列中值的某一層次結構的聚合。 GROU ...


    前幾天,看到一個群友用WITH ROLLUP運算符。由於自個兒沒用過,看到概念及結果都雲里霧裡的,所以突然來了興趣對生成結果測了一番。

    一、概念:

    WITH CUBE:生成的結果集顯示了所選列中值的所有組合的聚合。

    WITH ROLLUP:生成的結果集顯示了所選列中值的某一層次結構的聚合。

    GROUPING:當行由 WITH CUBE或WITH ROLLUP運算符添加時,該函數將導致附加列的輸出值為 1;當行不由 CUBE 或 ROLLUP 運算符添加時,該函數將導致附加列的輸出值為 0。僅在與包含 CUBE 或 ROLLUP 運算符的 GROUP BY 子句相關聯的選擇列表中才允許分組。

    二、測試:

    1、建立臨時表

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          --成績
)

     2、插入測試數據

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表結果:

    3、GROUP BY

    拋磚引玉,看看常用的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

    4、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

    結果與上面一致。

    其它欄位優先跟哪個欄位組合、最終怎樣排序?呃,測過,沒搞清楚……

    5、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

    結果與上面一致。

    6、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

     好了,原理測試及應用就到這裡結束了。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • MySQL DDL操作執行的三種方式 1,INPLACE,在進行DDL操作時,不影響表的讀&寫,可以正常執行表上的DML操作,避免與COPY方法相關的磁碟I/O和CPU周期,從而最小化資料庫的總體負載。 最小化負載有助於在DDL操作期間保持良好的性能和高吞吐量。 2,COPY,不允許併發執行過多個D ...
  • 在註冊表中找到 HKEY_CURRENT_USER\Software 選中其中的類似下列文件名的文件 HKEY_CURRENT_USER\Software\{d58cb4b1-47f3-45cb-a209-f298d0c3f756} HKEY_CURRENT_USER\Software\{FBC48 ...
  • 許多時候當要使用Mysql時,會遇到如下情況: 1. 信息比較重要,希望通信被加密。2. 一些埠,比如3306埠,被路由器禁用。 對第一個問題的一個比較直接的解決辦法就是更改mysql的代碼,或者是使用一些證書,不過這種辦法顯然不是很簡單。 這裡要介紹另外一種方法,就是利用SSH通道來連接遠程的 ...
  • [root@test153 ~]# /usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql_data1 /usr/local/mysql/bin/my ...
  • 創建表空間及用戶CREATE TABLESPACE OracleDBFDATAFILE 'D:\app\zhoulx\oradata\bdc\OracleDBF.DBF' SIZE 100M AUTOEXTEND ON NEXT 20M MAXSIZE UNLIMITED -- 這裡是你設置資料庫存 ...
  • 1.select * from SYS_DICT as of timestamp to_timestamp('2019-11-05 10:00:00','yyyy-mm-dd hh24:mi:ss'); 時間點在刪除數據之前,又儘量精確 sys_dict 是表名 2.insert into SYS_ ...
  • 阿裡開發手冊的描述,禁止多表join: 手冊上寫著【強制】,相信很多同學項目裡面的代碼都不滿足這個要求。 但是關鍵問題是:不用join,這SQL究竟要怎麼寫?! 分解關聯查詢 即對每個要關聯的表進行單表查詢,然後將結果在應用程式中進行關聯。下麵的這個查詢: 可以分解成下麵這些查詢來代替: 但是該方案 ...
  • 基本環境 elasticsearch版本:6.3.1 客戶端環境:kibana 6.3.4、Java8應用程式模塊。 其中kibana主要用於數據查詢診斷和查閱日誌,Java8為主要的客戶端,數據插入和查詢都是由Java實現的。 案例介紹 使用elasticsearch存儲訂單的主要信息,docum ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...