国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

擴(kuò)展GROUP BY之ROLLUP

IT那活兒 / 1338人閱讀
擴(kuò)展GROUP BY之ROLLUP
點(diǎn)擊上方“IT那活兒”公眾號(hào),關(guān)注后了解更多內(nèi)容,不管IT什么活兒,干就完了!!!

擴(kuò)展GROUP BY概述

在本章的開頭已經(jīng)簡(jiǎn)單描述了擴(kuò)展GROUP BY的應(yīng)用場(chǎng)景,Oracle擴(kuò)展GROUP BY允許使用SQL語(yǔ)句對(duì)數(shù)據(jù)匯總結(jié)果進(jìn)行多維展現(xiàn),從而生成復(fù)雜的報(bào)表,為決策者提供有效的數(shù)據(jù)支持。最重要的是,Oracle9i之后,擴(kuò)展GROUP BY的功能已經(jīng)趨于完善,能夠滿足大部分多維數(shù)據(jù)分析統(tǒng)計(jì)的工作。

主要表現(xiàn)在

  • ROLLUP、CUBE、GROUPING SETS擴(kuò)展GROUP BY子句提供了不同多維分組統(tǒng)計(jì)功能。
  • 3個(gè)擴(kuò)展分組函數(shù):GROUPING、GROUPING_ID、GROUP_ID提供擴(kuò)展GROUP BY的輔助功能:提供區(qū)別結(jié)果行屬于哪個(gè)分組級(jí)別,區(qū)分NULL值,建立有意義的報(bào)表,對(duì)匯總結(jié)果排序,過濾結(jié)果行等功能。
  • 對(duì)擴(kuò)展GROUP BY允許按重復(fù)列分組、組合列分組、部分分組、連接分組等復(fù)雜功能,另外GROUPING SETS可以接受CUBE、ROLLUP操作作為參數(shù),這些功能使擴(kuò)展GROUP BY更加強(qiáng)大。
通過SQL語(yǔ)句對(duì)上述功能的組合使用,就可以實(shí)現(xiàn)制作復(fù)雜的多維分析報(bào)表的功能。針對(duì)不同維度的報(bào)表統(tǒng)計(jì),使用擴(kuò)展GROUP BY的強(qiáng)大功能很容易實(shí)現(xiàn),而且SQL編寫更簡(jiǎn)單,性能也比同等的UNION ALL更好,在后面的內(nèi)容中,我們會(huì)見識(shí)到強(qiáng)大的擴(kuò)展GROUP BY功能。
還需要強(qiáng)調(diào)一點(diǎn),擴(kuò)展GROUP BY還是需要符合GROUP BY的相關(guān)語(yǔ)法語(yǔ)義規(guī)則的。比如SELECT中引用的列必須是分組列。

本章的表DEPT和EMP都來自于SCOTT用戶下,雖然表比較簡(jiǎn)單,但是足以能說明擴(kuò)展GROUP BY的功能。下面開始進(jìn)入主要內(nèi)容,探討強(qiáng)大的擴(kuò)展GROUP BY功能。


ROLLUP

在數(shù)據(jù)倉(cāng)庫(kù)系統(tǒng)中,一般多維分析報(bào)表,光有標(biāo)準(zhǔn)分組還不行,小計(jì)和合計(jì)往往是報(bào)表的核心內(nèi)容,這種需求使用ROLLUP很常見,如果使用同等的UNION ALL實(shí)現(xiàn),ROLLUP中的列越多,則需要寫的SQL語(yǔ)句就越復(fù)雜,所以與UNION ALL相比,ROLLUP寫法簡(jiǎn)單,而且性能一般更好。本章主要探討普通ROLLUP和部分ROLLUP提供的強(qiáng)大功能。

2.1 UNION ALL實(shí)現(xiàn)ROLLUP功能

假設(shè)有這樣的需求:

  • 1)統(tǒng)計(jì)每個(gè)部門每個(gè)職位的薪水和
  • 2) 統(tǒng)計(jì)每個(gè)部門所有職位的薪水小計(jì)
  • 3)統(tǒng)計(jì)所有部門所有職位的薪水合計(jì)
  • 4)需要顯示部門名、職位名和累加后的薪水值
如果不知道Oracle中有擴(kuò)展GROUP BY功能,那么很容易想起使用UNION ALL解決,的確在Oracle8i之前,沒有擴(kuò)展GROUP BY功能,就要使用UNION ALL解決了,寫3條SQL分別完成3個(gè)分組功能,然后用UNION ALL連接:
--需求1實(shí)現(xiàn)
SELECT  a.dname,b.job,SUM(b.sal) sum_sal
FROM dept a,emp b
WHERE a.deptno = b.deptno
GROUP  BY a.dname,b.job
UNION ALL

--需求2實(shí)現(xiàn)
SELECT  a.dname,NULL, SUM(b.sal) sum_sal
FROM dept a,emp b
WHERE a.deptno = b.deptno
GROUP  BY a.dname
UNION ALL

--需求3實(shí)現(xiàn)
SELECT  NULL,NULL, SUM(b.sal) sum_sal
FROM dept a,emp b
WHERE a.deptno = b.deptno;
顯示結(jié)果如下:
DNAME JOB SUM_SAL
---------------------------- ------------------ ----------
SALES MANAGER 2850
SALES CLERK                     950
ACCOUNTING MANAGER 2450
ACCOUNTING PRESIDENT 5000
ACCOUNTING CLERK                    1300
SALES SALESMAN 5600
RESEARCH MANAGER 2975
RESEARCH ANALYST 3000
RESEARCH CLERK                     800
ACCOUNTING 8750
RESEARCH 6775
SALES 9400
24925

已選擇13行。
執(zhí)行計(jì)劃:
----------------------------------------------------------
Plan hash value: 3113041979

------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | |    17 | 423 |    13  (70)| 00:00:01 |
| 1 |  UNION-ALL | |       | |            | |
| 2 |   HASH GROUP BY | |    12 | 336 |     5  (20)| 00:00:01 |
| 3 |    NESTED LOOPS | |    12 | 336 |     4   (0)| 00:00:01 |
| 4 |     TABLE ACCESS FULL | EMP |    12 | 180 |     3   (0)| 00:00:01 |
| 5 |     TABLE ACCESS BY INDEX ROWID| DEPT |     1 | 13 |     1   (0)| 00:00:01 |
|* 6 |      INDEX UNIQUE SCAN | PK_DEPT |     1 | |     0   (0)| 00:00:01 |
| 7 |   HASH GROUP BY | |     4 | 80 |     5  (20)| 00:00:01 |
| 8 |    NESTED LOOPS | |    12 | 240 |     4   (0)| 00:00:01 |
| 9 |     TABLE ACCESS FULL | EMP |    12 | 84 |     3   (0)| 00:00:01 |
| 10 |     TABLE ACCESS BY INDEX ROWID| DEPT |     1 | 13 |     1   (0)| 00:00:01 |
|* 11 |      INDEX UNIQUE SCAN | PK_DEPT |     1 | |     0   (0)| 00:00:01 |
| 12 |   SORT AGGREGATE | |     1 | 7 |            | |
|* 13 |    TABLE ACCESS FULL | EMP |    12 | 84 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

6 - access("A"."DEPTNO"="B"."DEPTNO")
11 - access("A"."DEPTNO"="B"."DEPTNO")
13 - filter("B"."DEPTNO" IS NOT NULL)

從執(zhí)行計(jì)劃可以看出,為了實(shí)現(xiàn)這樣的需求,需要多次訪問EMP、DEPT表以及DEPT表的索引,這里的測(cè)試數(shù)據(jù)很少而且表結(jié)構(gòu)簡(jiǎn)單,實(shí)際應(yīng)用中表結(jié)構(gòu)可能很復(fù)雜,經(jīng)常是多表關(guān)聯(lián),數(shù)據(jù)量可能達(dá)到百萬級(jí),千萬級(jí),甚至上億,那么使用UNION ALL,明顯性能低下,如果使用WITH子句將常規(guī)分組的結(jié)果固定下來,然后在此基礎(chǔ)上再聚合,效率可能比單純UNION ALL好,但是還是不夠完美,現(xiàn)在的需求是對(duì)2列進(jìn)行多維分析,如果是很多列呢?必然增加語(yǔ)句復(fù)雜度,類似地,CUBE,GROUPING SETS用UNION ALL改寫也有此類問題,何況擴(kuò)展GROUP BY還提供了很多復(fù)雜功能,用UNION ALL改寫就更加麻煩了。

試想對(duì)于上面的需求,如果Oracle能提供一個(gè)這樣的分組功能就好了:

  • 直接把分組的列按順序?qū)懺谝黄穑峁┮粋€(gè)簡(jiǎn)單的語(yǔ)法結(jié)構(gòu)。
  • 此語(yǔ)法結(jié)構(gòu)先進(jìn)行全分組:標(biāo)準(zhǔn)分組。
  • 然后這個(gè)語(yǔ)法結(jié)構(gòu)從右到左遞減列,做對(duì)應(yīng)維度的分組,實(shí)現(xiàn)小計(jì)和合計(jì)。
如果有實(shí)現(xiàn)這3個(gè)要求的語(yǔ)法結(jié)構(gòu),那么上述需求就能很容易地實(shí)現(xiàn),的確,Oracle提供了這樣的功能,那就是ROLLUP分組。

2.2 ROLLUP分組

Oracle使用ROLLUP對(duì)GROUP BY進(jìn)行擴(kuò)展:它允許計(jì)算標(biāo)準(zhǔn)分組以及相應(yīng)維度的小計(jì)、合計(jì)功能。ROLLUP的語(yǔ)法結(jié)構(gòu)很簡(jiǎn)單:
SELECT … GROUP BY ROLLUP(grouping_column_reference_list)
ROLLUP后面指定的列以逗號(hào)分割,ROLLUP的計(jì)算結(jié)果和其后面指定列的順序有關(guān),因?yàn)镽OLLUP分組過程具有方向性:先計(jì)算標(biāo)準(zhǔn)分組,然后列從右到左遞減計(jì)算更高一級(jí)的小計(jì),一直到列全部被選完,最后計(jì)算合計(jì)。這樣如果ROLLUP中指定n列,則整個(gè)計(jì)算過程中的分組方式有n+1種。下面就使用ROLLUP實(shí)現(xiàn)1.2.1的需求,如下:
SELECT  a.dname,b.job, SUM(b.sal) sum_sal
FROM dept a,emp b
WHERE a.deptno = b.deptno
GROUP  BY ROLLUP(a.dname,b.job);
顯示結(jié)果如下:
DNAME JOB SUM_SAL
---------------------------- ------------------ ----------
SALES CLERK                     950
SALES MANAGER 2850
SALES SALESMAN 5600
SALES 9400
RESEARCH CLERK                     800
RESEARCH ANALYST 3000
RESEARCH MANAGER 2975
RESEARCH 6775
ACCOUNTING CLERK                    1300
ACCOUNTING MANAGER 2450
ACCOUNTING PRESIDENT 5000
ACCOUNTING 8750
       24925

已選擇13行。
執(zhí)行計(jì)劃:
----------------------------------------------------------
Plan hash value: 503922295

-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | |    12 | 336 |     5  (20)| 00:00:01 |
| 1 |  SORT GROUP BY ROLLUP | |    12 | 336 |     5  (20)| 00:00:01 |
| 2 |   NESTED LOOPS | |    12 | 336 |     4   (0)| 00:00:01 |
| 3 |    TABLE ACCESS FULL | EMP |    12 | 180 |     3   (0)| 00:00:01 |
| 4 |    TABLE ACCESS BY INDEX ROWID| DEPT |     1 | 13 |     1   (0)| 00:00:01 |
|* 5 |     INDEX UNIQUE SCAN | PK_DEPT |     1 | |     0   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

5 - access("A"."DEPTNO"="B"."DEPTNO")
從上面的結(jié)果可以看出,使用ROLLUP只需要訪問EMP表一次,通過DEPT表的主鍵獲得ROWID回表查詢相關(guān)行,比前面的UNION ALL性能要好,而且從執(zhí)行計(jì)劃上看出有一個(gè)特別的操作:SORT GROUP BY ROLLUP,這說明:這里的ROLLUP的計(jì)算結(jié)果是有順序的,所以展示的結(jié)果很直觀,但是一般還是要顯式排序的,因?yàn)槟J(rèn)排序很多時(shí)候不符合業(yè)務(wù)需求,另外,默認(rèn)排序是受執(zhí)行計(jì)劃影響的,可能有的ROLLUP就無序了,在重復(fù)列分組中就會(huì)說到?jīng)]有排序的情況,對(duì)于顯式排序,后面說到的GROUPING_ID函數(shù)會(huì)專門解決擴(kuò)展分組排序問題。

ROLLUP分組具有方向性,從上面的結(jié)果看出,ROLLUP(a.dname,b.job)分組的過程是這樣的:

  • 標(biāo)準(zhǔn)分組:GROUP BY(a.dname,b.job),對(duì)每個(gè)部門每個(gè)職位進(jìn)行分組(我分析的時(shí)候經(jīng)常對(duì)GROUP BY加上括號(hào),其實(shí)沒有必要,只是為了更直觀而已)。
  • 從右到左遞減:GROUP BY(a.dname,NULL),其實(shí)這個(gè)NULL沒有必要使用,這里只是為了方便分析。這個(gè)過程是對(duì)上個(gè)級(jí)別分組的小計(jì),也就是對(duì)每個(gè)dname值,計(jì)算橫跨所有job的小計(jì)。
  • 最后合計(jì):相當(dāng)于GROUP BY (NULL,NULL)。
上面的ROLLUP只用了兩個(gè)列,如果有n個(gè)列,那么結(jié)果就是n+1種GROUP BY的組合,從右到左遞減的過程中,下一個(gè)分組就是對(duì)上一個(gè)分組的小計(jì),最后合計(jì),比如ROLLUP(a,b,c),那么有:

分組級(jí)別

描述

a,b,c

標(biāo)準(zhǔn)分組

a,b

對(duì)于每個(gè)a,b列值,計(jì)算橫跨c列的小計(jì)

a

對(duì)于每個(gè)a列值,計(jì)算橫跨b,c列的小計(jì)

合計(jì)匯總

合計(jì)


另外提一下,其實(shí)ROLLUP操作,如果使用HINT: expand_gset_to_union,那么則優(yōu)化器會(huì)將ROLLUP轉(zhuǎn)為對(duì)應(yīng)的UNION ALL操作,其它的GROUPING SETS、CUBE也可以,有興趣的可以試一下。

ROLLUP語(yǔ)法簡(jiǎn)單,而且具體處理過程也很簡(jiǎn)單,除了第1個(gè)是標(biāo)準(zhǔn)分組,然后就是列從右到左遞減的分組,最后合計(jì)。下面實(shí)現(xiàn)需求:

  • 計(jì)算每個(gè)入職時(shí)間(年)、部門、職位的標(biāo)準(zhǔn)分組的薪水和。
  • 計(jì)算每個(gè)入職時(shí)間(年)、部門的所有職位的薪水小計(jì)。
  • 計(jì)算每個(gè)入職時(shí)間(年)的所有部門所有職位的薪水小計(jì)。
  • 最后合計(jì)薪水,顯示入職時(shí)間(年)、部門名、職位名。
從上面學(xué)到的ROLLUP知識(shí),可以很容易地編寫SQL實(shí)現(xiàn)上述需求,將hire_date格式化到年,部門名dname,職位名job按順序放到ROLLUP中即可。
SELECT to_char(b.hiredate,yyyy) hire_year,a.dname,b.job, SUM(sal) sum_sal
FROM dept a,emp b
WHERE a.deptno = b.deptno
GROUP BY ROLLUP(to_char(b.hiredate,yyyy),a.dname,b.job);
結(jié)果如下:
HIRE_YEA DNAME JOB SUM_SAL
-------- ---------------------------- ------------------ ----------
1980     RESEARCH CLERK                     800
1980     RESEARCH 800
1980                                                            800
1981     SALES CLERK                     950
1981     SALES MANAGER 2850
1981     SALES SALESMAN 5600
1981     SALES 9400
1981     RESEARCH ANALYST 3000
1981     RESEARCH MANAGER 2975
1981     RESEARCH 5975
1981     ACCOUNTING MANAGER 2450
1981     ACCOUNTING PRESIDENT 5000
1981     ACCOUNTING 7450
1981                                                          22825
1982     ACCOUNTING CLERK                    1300
1982     ACCOUNTING 1300
1982                                                           1300
                                         24925
從結(jié)果看出,編寫的SQL是實(shí)現(xiàn)了上述需求的。下面選些結(jié)果中的典型記錄對(duì)此結(jié)果進(jìn)行分析,其它行分析類似:

相關(guān)行

描述

第7行

對(duì)第4、5、6行的所有JOB進(jìn)行小計(jì)

第14行

對(duì)第7行、第13行的所有DNAME、JOB進(jìn)行小計(jì),當(dāng)然也相當(dāng)于對(duì)4-6、8-12行所有DNAME、JOB的小計(jì)。

最后一行

對(duì)所有入職日期(精確到年)、DNAME、JOB進(jìn)行合計(jì)


因?yàn)镽OLLUP分組過程具有方向性,所以通過改變ROLLUP中列的順序就可以達(dá)到改變報(bào)表結(jié)果和含義的目的。比如將前面的ROLLUP(dname,job)改為ROLLUP(job,dname)則含義就發(fā)生了變化,現(xiàn)在需要查詢的就是標(biāo)準(zhǔn)分組、計(jì)算每個(gè)job的所有部門的小計(jì)、最后合計(jì),這里就兩個(gè)列,也就是小計(jì)的含義發(fā)生了變化,請(qǐng)看:

SELECT  b.job,a.dname, SUM(b.sal) sum_sal
FROM dept a,emp b
WHERE a.deptno = b.deptno
GROUP  BY ROLLUP(b.job,a.dname);
顯示結(jié)果如下:
JOB DNAME SUM_SAL
------------------ ---------------------------- ----------
CLERK              SALES 950
CLERK              RESEARCH 800
CLERK              ACCOUNTING 1300
CLERK                                                 3050
ANALYST RESEARCH 3000
ANALYST 3000
MANAGER SALES 2850
MANAGER RESEARCH 2975
MANAGER ACCOUNTING 2450
MANAGER 8275
SALESMAN SALES 5600
SALESMAN 5600
PRESIDENT ACCOUNTING 5000
PRESIDENT 5000
24925

已選擇15行。
從結(jié)果看出,與ROLLUP(dname,job)的確發(fā)生了變化,小計(jì)是對(duì)每個(gè)職位的所有部門進(jìn)行小計(jì),一定要牢記ROLLUP列的順序?qū)Y(jié)果的影響,才能靈活地使用ROLLUP實(shí)現(xiàn)多維分析統(tǒng)計(jì)。

2.3 部分ROLLUP分組

2.2中的ROLLUP是普通的ROLLUP,有標(biāo)準(zhǔn)分組、多種小計(jì)、合計(jì)。如果現(xiàn)在的報(bào)表不需要某些小計(jì)、合計(jì),那么怎么辦呢?有辦法,Oracle提供了部分ROLLUP分組功能,也就說將部分列從ROLLUP中移出來,放在GROUP BY中,這樣合計(jì)肯定沒有了,某些小計(jì)也沒有了。如ROLLUP(to_char(b.hiredate,yyyy),a.dname,b.job),現(xiàn)在不需要每個(gè)入職時(shí)間(年)的所有部門所有職位的薪水小計(jì),合計(jì)也不需要,那么改寫為:
SELECT to_char(b.hiredate,yyyy) hire_year,a.dname,b.job, SUM(sal) sum_sal
FROM dept a,emp b
WHERE a.deptno = b.deptno
GROUP BY to_char(b.hiredate,yyyy),a.dname,ROLLUP(b.job);
將hiredate和dname從ROLLUP中移出來,就可以將每個(gè)入職時(shí)間(年)的所有部門所有職位的薪水小計(jì)以及合計(jì)剔除。最終只查詢標(biāo)準(zhǔn)分組和每個(gè)入職時(shí)間(年)、部門的所有職位的小計(jì)。部分ROLLUP提供了報(bào)表的額外選擇,當(dāng)然,很多情況下合計(jì)還是需要的,能不能既剔除部分小計(jì),又能保留合計(jì)呢?有很多方法,有時(shí)候可以很容易用組合列分組、連接分組等解決,有時(shí)候使用擴(kuò)展分組函數(shù)剔除比較簡(jiǎn)單,根據(jù)具體情況使用合適方法,部分CUBE類似。

ROLLUP總結(jié)

在數(shù)據(jù)倉(cāng)庫(kù)系統(tǒng)中,經(jīng)常需要對(duì)相關(guān)表進(jìn)行多維匯總統(tǒng)計(jì),如果分組有規(guī)律,比如先進(jìn)行常規(guī)分組,在常規(guī)分組基礎(chǔ)上通過將列從右到左移動(dòng),然后進(jìn)行更高一級(jí)的小計(jì),最后合計(jì),這樣一般就需要使用ROLLUP,ROLLUP結(jié)果和列的順序有關(guān),順序不同結(jié)果則不同,這為報(bào)表實(shí)現(xiàn)提供了很大的靈活性。
ROLLUP中指定n列,則根據(jù)ROLLUP的分組過程可以知道,分組方式有n+1種。另外部分ROLLUP可以剔除某些不需要的小計(jì)和合計(jì),只要根據(jù)需求將相關(guān)列從ROLLUP中移出,放到GROUP BY中即可。


本文作者:丁 俊(上海新炬中北團(tuán)隊(duì))

本文來源:“IT那活兒”公眾號(hào)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/129114.html

相關(guān)文章

  • GROUP BY你都不會(huì)!ROLLUP,CUBE,GROUPPING詳解

    摘要:當(dāng)向傳入一列時(shí),會(huì)得到一個(gè)總計(jì)行。結(jié)果當(dāng)向傳遞兩列時(shí),將會(huì)按照這兩列進(jìn)行分組,同時(shí)按照第一列的分組結(jié)果返回小計(jì)行。結(jié)果可以看出來結(jié)果是按照工廠和部門分別分組匯總的。選擇的就表示兩列都不為空。 Group By Group By 誰(shuí)不會(huì)啊?這不是最簡(jiǎn)單的嗎?越是簡(jiǎn)單的東西,我們?cè)綍?huì)忽略掉他,因?yàn)槲覀儾辉敢庠偃ド钊肓私馑? 小時(shí) SQL 極速入門(一)1 小時(shí) SQL 極速入門(二)1 ...

    only_do 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<