Oracle 中關於 Group By 子句與多行函數嵌套搭配使用的注意事項

[toc]

你需要知道的

提到 Group by 子句,你需要先理解一個東西:函數的分類。提到函數分類,你腦海裏面需要瞬間想到Oracle中的函數分類:單行函數(Single-row functions)、多行函數(Multiple-row functions)。請把中文英文都背下來,也就這麼兩個,這是Oracle的函數分類的體系,很重要。以後再遇到這個知識點,你至少能夠胸有成竹,張口就來。

啥叫單行函數

舉個現炒板栗:你說你要查 EMP 表中,所有人員的名字和他對應的工資,於是發出下面的語句並得到結果。

SQL> select ename,sal from emp;

ENAME			    SAL
-------------------- ----------
SMITH			    800
ALLEN			   1600
WARD			   1250
JONES			   2975
MARTIN			   1250
BLAKE			   2850
CLARK			   2450
SCOTT			   3000
KING			   5000
TURNER			   1500
ADAMS			   1100
JAMES			    950
FORD			   3000
MILLER			   1300

14 rows selected.

你會發現,14行結果中,每個人的名字都是大寫(注意:Oracle 語句不區分大小寫,但是存的值是區分大小寫的,SCOTT 和 scott 是兩個值)。你說你看的不習慣,問能否把名字處理成“小寫”字母來顯示?

這裏我們給出一個東西 lower(),它是什麼?你先不管,先叫它“函數”,我們用它把名字處理一下:發出以下命令並得到結果。

SQL> select lower(ename),sal from emp;

LOWER(ENAME)		    SAL
-------------------- ----------
smith			    800
allen			   1600
ward			   1250
jones			   2975
martin			   1250
blake			   2850
clark			   2450
scott			   3000
king			   5000
turner			   1500
adams			   1100
james			    950
ford			   3000
miller			   1300

14 rows selected.

你會發現,名字通過 lower 函數處理之後,全部變爲了小寫,更重要的是,處理完畢後,結果集的行數(14行)和處理前結果集的行數(14行)完全一致,也就是說,用了這個 lower 函數處理數值,最終的結果條目數是一比一的呈現,於是,我們稱 lower 這個函數爲:單行函數(針對結果集的每一行都返回一個值)。

啥叫多行函數

你說你要查 EMP 表中,所有人員工資的總和,於是發出下面的語句並得到結果。

SQL> select sum(sal) from emp;

  SUM(SAL)
----------
     29025

這個 sum 是什麼,也是個函數,你會發現,使用了這個 sum 求和函數後,最終返回一行數據。原來 14 行,使用了 sum 變爲 1 行,於是,我們稱 sum 這個函數爲:多行函數(針對<font color=#FF0000>每個結果集</font>只返回一個值)。<font color=#FF0000>不要這麼記</font>:針對多行只返回一個值的稱作多行函數。

如何理解<每個結果集>這個概念

再看個例子:按照部門,查詢每個部門的工資總和,於是發出下面的語句並得到結果。

SQL> select deptno,sum(sal) from emp group by deptno order by 1;

    DEPTNO   SUM(SAL)
---------- ----------
	10	 8750
	20	10875
	30	 9400

呈現的結果爲<font color=#FF0000>3行</font>數據,處理前一共 14 行,通過 sum 求和函數處理後得到 3 行數據,請問:sum 是多行函數嗎?當然是!這裏涉及到一個基本概念的理解,如果你認爲:~~<font color=#FF0000>針對多行返回一行稱爲多行函數。</font>~~那麼我通過這個例子就可以反駁你,因爲我針對多行(14行)返回了 3 行,不是 1 行。你能告訴我說 sum 不是多行函數嗎?所以,這種說法本身就存在歧義。

而官方教材對多行函數的精準描述是這樣的:<font color=#FF0000>Return one result per set of rows.</font>什麼意思?針對每個行集(或理解爲結果集)返回一個值(就是一行)。這麼記,你對多行函數的概念就不會迷迷糊糊了。

那如何理解<font color=#FF0000>行集(結果集)</font>這個概念?我們求所有部門的工資總和 sum(sal) ,這個行集就是 14 行數據,最終返回 1 行,就是總額。我們按照部門,求每個部門的工資總和,因此要按照部門分開,求出每個部門的工資總和,我們先看下 10 號部門的行數:

SQL> select count(1) from emp where deptno=10;

  COUNT(1)
----------
	 3

10 號部門有 3 行數據,因此,對於 10 號部門工資求和的行集就是 3 行,通過計算這 3 行的數據,最終返回 1 行,就是 10 號部門的工資總額。

再來看 20 號部門:這個部門一共 5 行數據,因此,對於 20 號部門來說,行集就是 5 行,最終返回 1 行,就是 20 號部門的工資總額。

SQL> select count(1) from emp where deptno=20;

  COUNT(1)
----------
	 5

30 號部門也一樣:一共 6 行數據,因此,對於 30 號部門來說,行集就是 6 行,最終返回 1 行,就是 30 號部門的工資總額。

SQL> select count(1) from emp where deptno=30;

  COUNT(1)
----------
	 6

Group by 子句使用規則

  • 使用多行函數不一定要使用 group by 子句

例如:查詢所有部門工資總和

SQL> select sum(sal) from emp;
  • select 子句中包含的所有字段(除使用了多行函數的字段)都必須包含在 group by 子句中

例如:按照部門分組查詢每個部門的工資總和

SQL> select deptno,sum(sal) from emp group by deptno;

注意:select 子句中包含兩個字段 deptno 和 sum(sal) ,因爲 sal 字段使用了多行函數,所以在後面 group by 子句中只需要包含 deptno 即可。

  • select 子句所有字段都使用了多行函數,group by 子句可以根據需求指定分組字段
# 以下語句都是正確的。從業務邏輯層面來說,毫無意義,只是爲了展示語句規則。
SQL> select sum(sal) from emp group by ename;
SQL> select sum(sal) from emp group by ename,empno;
SQL> select sum(sal) from emp group by ename,empno,sal;
  • 多行函數嵌套必須使用 group by 子句

注意下嵌套函數:嵌套函數不是一個函數,而是對函數疊加使用的描述。例如:求出哪個部門工資總和最大。

SQL> select max(sum(sal)) from emp group by deptno;

MAX(SUM(SAL))
-------------
	10875

這個 max(sum(sal)) 就是一個嵌套函數,多行函數嵌套最多嵌套 2 層。單行函數嵌套無限制。

  • select子句中不允許出現除多行函數嵌套的其他字段

例如:下面語句報錯

SQL> select deptno,max(sum(sal)) from emp group by deptno;
select deptno,max(sum(sal)) from emp group by deptno
       *
ERROR at line 1:
ORA-00937: not a single-group group function

看一道 071 考題

Which query is valid?

A. SELECT dept_id,join_date,sum(salary) FROM employees GROUP BY dept_id,join_date;
B. SELECT dept_id,join_date,sum(salary) FROM employees GROUP BY dept_id;
C. SELECT dept_id,MAX(AVG(salary)) FROM employees GROUP BY dept_id;
D. SELECT dept_id,AVG(MAX(salary)) FROM employees GROUP BY dept_id;

答案:<font color=#F8F8FF>A</font>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章