GROUP_ID
首先我們看看官方的解釋:
大意是GROUP_ID用於區分相同分組標准的分組統計結果。
解釋起來比較抽象,下面我們來看看具體的案例。
例1:單一分組
SQL> select group_id(),deptno,sum(sal) from emp group by rollup(deptno); GROUP_ID() DEPTNO SUM(SAL) ---------- ---------- ---------- 0 10 8750 0 20 10875 0 30 9400 0 29025
rollup(deptno)只是一個唯一的分組,所以產生的group_id()為0,代表這是同一個分組的結果。
下面我們來看看重復分組的情況
例2:重復分組
SQL> select group_id(),deptno,sum(sal) from emp group by rollup(deptno,deptno); GROUP_ID() DEPTNO SUM(SAL) ---------- ---------- ---------- 0 10 8750 0 20 10875 0 30 9400 1 10 8750 1 20 10875 1 30 9400 0 29025 7 rows selected.
group_id()為1代表這些是重復的分組。
注意:可通過having group_id() <1來剔除重復的分組。
老實說,我也看不出GROUP_ID在實際工作中的應用場景,姑且先記着。
GROUPING
其語法為:GROUPING(expr)
下面我們來看看官方的解釋:
即GROUPING函數用於區分分組后的普通行和聚合行。如果是聚合行,則返回1,反之,則是0。
下面我們來看看具體的案例:
SQL> select grouping(deptno),grouping(job),deptno,job,sum(sal) from emp group by rollup(deptno,job); GROUPING(DEPTNO) GROUPING(JOB) DEPTNO JOB SUM(SAL) ---------------- ------------- ---------- --------- ---------- 0 0 10 CLERK 1300 0 0 10 MANAGER 2450 0 0 10 PRESIDENT 5000 0 1 10 8750 0 0 20 CLERK 1900 0 0 20 ANALYST 6000 0 0 20 MANAGER 2975 0 1 20 10875 0 0 30 CLERK 950 0 0 30 MANAGER 2850 0 0 30 SALESMAN 5600 0 1 30 9400 1 1 29025 13 rows selected.
首先我們看GROUPING(DEPTNO)這一列的結果,不難看出,凡是基於DEPTNO的匯總,GROUPING的結果均為0,因為最后一行是總的匯總,所以GROUPING的值為1.
基於這個邏輯,可以看出GROUPING(JOB)的值也是吻合的。
GROUPING_ID
GROUPING_ID是GROUPING的增強版,與GROUPING只能帶一個表達式不同,它能帶多個表達式。
語法如下:
GROUPING_ID(expr1, expr2, expr3,….)
下面我們來看看官方的解釋:
GROUPING_ID在功能上相當於將多個GROUPING函數的結果串接成二進制數,返回的是這個二進制數對應的十進制數。
下面我們來看看具體的案例:
SQL> select grouping(deptno)g_d,grouping(job)g_j,grouping_id(deptno)gi_d,grouping_id(job)gi_j,grouping_id(deptno,job)gi_dj,grouping_id(job,deptno)gi_jd,deptno,job,sum(sal) from emp group by cube(deptno,job); G_D G_J GI_D GI_J GI_DJ GI_JD DEPTNO JOB SUM(SAL) ---------- ---------- ---------- ---------- ---------- ---------- ---------- --------- ---------- 1 1 1 1 3 3 29025 1 0 1 0 2 1 CLERK 4150 1 0 1 0 2 1 ANALYST 6000 1 0 1 0 2 1 MANAGER 8275 1 0 1 0 2 1 SALESMAN 5600 1 0 1 0 2 1 PRESIDENT 5000 0 1 0 1 1 2 10 8750 0 0 0 0 0 0 10 CLERK 1300 0 0 0 0 0 0 10 MANAGER 2450 0 0 0 0 0 0 10 PRESIDENT 5000 0 1 0 1 1 2 20 10875 0 0 0 0 0 0 20 CLERK 1900 0 0 0 0 0 0 20 ANALYST 6000 0 0 0 0 0 0 20 MANAGER 2975 0 1 0 1 1 2 30 9400 0 0 0 0 0 0 30 CLERK 950 0 0 0 0 0 0 30 MANAGER 2850 0 0 0 0 0 0 30 SALESMAN 5600 18 rows selected.
大家看到這個案例估計都有點暈。。。
之所以這樣提供,是為了呈現一個直觀的結果進行對比。
解讀這個結果,需要注意以下兩點:
1> 若本行是某expr的匯總,那么該expr對應的二進制數位置為0否則置為1。
2> GROUPING_ID(expr1, expr2, expr3,….)的值其實是對應GROUPING(expr1),GROUPING(expr2),GROUPING(expr3)...值的串接。
首先看第一列,第三列,雖然一個是grouping(deptno),一個是grouping_id(deptno),因為只有一個表達式,所以兩者的結果是一樣的。第二列,第四列同樣如此。
第五列的結果是第一列和第二列的數值的串接,然后返回的十進制數,以第二行為例,GI_DJ=2其實是二進制10轉化為十進制后的數,其中1為G_D的值,0為G_J的值。
而GI_JD=1則是二進制01轉化為十進制后的數,其中0為G_J的值,1為G_D的值。注意,串接的順序為GROUPING_ID中表達式的順序。
說了這么多,下面我們來看一個利用GROUPING_ID實現行列轉換的案例。
with t as ( select grouping_id(deptno,job)gi_dj,deptno,job,count(*)cnt from emp group by cube(deptno,job)), t1 as ( select decode(gi_dj,0,deptno,1,deptno,99) deptno,decode(gi_dj,1,cnt,3,cnt)sub_total, decode(job,'CLERK',cnt) c1,decode(job,'ANALYST',cnt)c2,decode(job,'MANAGER',cnt)c3, decode(job,'SALESMAN',cnt)c4,decode(job,'PRESIDENT',cnt)c5 from t) select deptno,max(sub_total) sub_total,max(c1)clerk,max(c2)analyst, max(c3)manager,max(c4)salesman,max(c5)president from t1 group by deptno order by deptno;
最后生成的結果如下:
DEPTNO SUB_TOTAL CLERK ANALYST MANAGER SALESMAN PRESIDENT ---------- ---------- ---------- --------- ---------- ---------- ---------- 10 3 1 1 1 20 5 2 2 1 30 6 1 1 4 99 14 4 2 3 4 1
其中,99代表合計,sub_total代表小計。這種統計類的需求在實際生產中還是應用蠻廣的。
當然,該結果也可利用PIVOT函數實現,具體語句如下:
with t as(select grouping_id(deptno,job)gi_dj,deptno,job,count(*)cnt from emp group by cube(deptno,job)), t1 as (select decode(gi_dj,0,deptno,1,deptno,99)deptno,decode(gi_dj,0,job,2,job,9)job,cnt from t) select * from (select * from t1)pivot(sum(cnt)for job in ('9','CLERK','ANALYST','MANAGER','SALESMAN','PRESIDENT')) order by deptno;
參考資料:
1> http://docs.oracle.com/cd/E11882_01/server.112/e41084/functions070.htm#SQLRF00646
2> http://docs.oracle.com/cd/E11882_01/server.112/e41084/functions071.htm#SQLRF00647
3> http://docs.oracle.com/cd/E11882_01/server.112/e41084/functions072.htm#SQLRF00648